Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-26 19:58 UTC

ttsim-dev / ttsim

The computing engine powering GETTSIM

PythonAGPL-3.0★ 2 estrellas⑂ 0 forksdesde jul 2025Ver en GitHub ↗

ttsim-dev/ttsim tiene un índice de salud de 70 sobre 100, lo que lo sitúa en la banda Bueno. Su puntuación más alta es Vitality (86/100) y la más baja, Community & Adoption (34/100). Se actualizó por última vez hoy. 3 personas concentran la mayor parte del trabajo reciente.

70
global / 100
Bueno

Í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.

70
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

6 seguidores7 repositorios públicosdesde feb 2025

Este repositorio está respaldado por una organización: una custodia compartida y responsable que puede sobrevivir a cualquier mantenedor individual.

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicaciónEtiquetas
PyPIttsim-backend1.2.1-10hace 62 díasbenefitseconomicspensionstaxestransfers

Métricas por categoría

Vitalidad

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

86Excelente · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 0 días
15.2/36Cadencia de commits — 22/52 semanas con commits
16.2/18Volumen de commits — 62 commits en el último año
10/10OpenSSF Scorecard: Maintained — 18 commit(s) and 10 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year62
human_commit_share0,97
days_since_last_push0
active_weeks_last_year22
Cómo se puntúa
27/27Publica versiones — 10 versiones publicadas
36/36Recencia de las versiones — última versión hace 62 días
27/27Cadencia de publicación — una versión cada ~33,9 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count10
latest_release_tagv1.2.1
releases_from_tagsno
days_since_latest_release62
mean_days_between_releases33,9
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?

34En riesgo · 18% del índice global
Cómo se puntúa
0/60Estrellas — 2 estrellas
0/25Forks — 0 forks
0/15Observadores — 2 observadores
Datos de entrada utilizados
forks0
stars2
watchers2
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (AGPL-3.0)
0/18Guía CONTRIBUTING
13.5/13.5Código de conducta
0/7.2Plantilla de issues
6.3/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
has_contributingno
has_issue_templateno
has_code_of_conduct
has_pull_request_template

Sostenibilidad y Gobernanza

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

74Bueno · 24% del índice global
Cómo se puntúa
36/54Factor bus — la mitad de los commits recae en 3 contribuyente(s)
16.8/22.5Distribución de commits — el principal contribuyente firma el 26% de los commits
13.5/13.5Amplitud de contribuyentes — 28 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 16 contributing companies or organizations
Datos de entrada utilizados
bus_factor3
contributors_sampled28
top_contributor_share0,255
Cómo se puntúa
36.4/46.8Resolución de issues — 78% de issues cerradas
29.2/38.3Aceptación de PR — 81/106 PR decididos fusionados
13.5/15OpenSSF Scorecard: Code-Review — Found 27/30 approved changesets -- score normalized to 9
Datos de entrada utilizados
merged_prs81
open_issues8
closed_issues28
issue_closed_ratio0,778
closed_unmerged_prs25
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
6.1/25Alcance del propietario — 6 seguidores de ttsim-dev
9.4/25Trayectoria — 7 repos públicos, cuenta de ~1 años
Datos de entrada utilizados
followers6
owner_typeOrganization
is_verified
owner_loginttsim-dev
public_repos7
account_age_days516
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en pypi
35/35Recencia de publicación — última publicación hace 62 días
20/20Historial de versiones — 10 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesttsim-backend
ecosystemspypi
any_deprecatedno
min_days_since_publish62

Calidad de Ingeniería

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

78Bueno · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 2 flujo(s) de trabajo
24/24Pruebas presentes
16/16Configuración de linter
9.6/9.6Hooks de pre-commit
0/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 28 out of 28 merged PRs checked by a CI test -- score normalized to 10
Datos de entrada utilizados
has_ci
has_tests
has_editorconfigno
has_linter_config
has_precommit_config

Documentación

55Moderado
Cómo se puntúa
30/30README
0/25Directorio de documentación
15/15Sitio de documentación / página del proyecto — https://gettsim.readthedocs.io/
10/10Descripción del repositorio
0/10Topics
0/10Wiki
Datos de entrada utilizados
topics
has_wikino
homepagehttps://gettsim.readthedocs.io/
has_readme
has_docs_dirno
has_description

Seguridad

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

73Bueno · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — sin datos
2.5/2.5CI-Tests — 28 out of 28 merged PRs checked by a CI test -- score normalized to 10
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
6.8/7.5Code-Review — Found 27/30 approved changesets -- score normalized to 9
2.5/2.5Contributors — project has 16 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
7.5/7.5Maintained — 18 commit(s) and 10 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — sin datos
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate6,6
Excluidos de la puntuación (sin datos o no aplicable): branch_protection, signed_releases. Los pesos restantes se han renormalizado.
Cómo se puntúa
35/35Dependencias directas libres de avisos conocidos — ninguna dependencia directa tiene un aviso conocido
25/25Dependencias indirectas libres de avisos conocidos — ninguna dependencia indirecta tiene un aviso conocido
0/40Sin avisos pendientes — ningún aviso tiene fecha de publicación
Datos de entrada utilizados
sourceosv
advisories0
affected_packages0
assessed_packages49
unassessed_packages0
affected_by_severitynone
direct_affected_packages0
Excluidos de la puntuación (sin datos o no aplicable): Sin avisos pendientes. Los pesos restantes se han renormalizado. Se cotejó el cierre de dependencias en tiempo de ejecución de pypi:ttsim-backend@1.2.1 —lo que arrastra la instalación del paquete publicado—: 49 paquetes. No se analiza la alcanzabilidad.

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.

60Moderado · 0% del índice global
Cómo se puntúa
45/45Instrucciones para agentes — AGENTS.md, CLAUDE.md, GEMINI.md
0/15Documentación legible por máquinas (llms.txt)
40/40Historial de commits legible — 74 de 97 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,763
agent_instruction_filesAGENTS.md, CLAUDE.md, GEMINI.md
agent_instruction_max_bytes6112
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
11/11Configuración de lint / formato
0/11Verificación estática de tipos
0/10Entorno reproducible
10/10Práctica demostrada con agentes — 23 de los últimos 100 commits con autoría o crédito de agente
8/8Mantenimiento automatizado — 2 de los últimos 100 commits son actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_tests
lockfiles
has_dockerfileno
typed_languageno
bootstrap_files
has_devcontainerno
has_linter_config
typecheck_configs
agent_commit_share0,23
toolchain_manifests
dependency_bot_commit_share0,02
Cómo se puntúa
0/45Código verificable por tipos — Python sin configuración de verificación de tipos
54.5/55Tamaños de archivo manejables — 1/115 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languagePython
largest_source_bytes61.629
source_files_sampled115
oversized_source_files1
Cómo se puntúa
0/40Esquema de API (OpenAPI/GraphQL/proto)
0/20Servidor MCP
40/40Ejemplos ejecutables — notebooks
Datos de entrada utilizados
example_dirsnotebooks
has_mcp_signalno
api_schema_files

Datos clave

2estrellas de GitHub
28contribuidores
62commits en los últimos 12 meses
0días desde el último push
10versiones publicadas
3factor bus
8issues abiertas
PyPIecosistemas de paquetes

Advertencias de recopilación de datos

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • Could not fetch pypi package 'mettsim' from its registry
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Más detalle

OpenSSF Scorecard 6.6 / 10
6.6agregado

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-26 19:58 UTC

10Binary-Artifactsno binaries found in the repo
n/dBranch-Protectioninternal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
10CI-Tests28 out of 28 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
9Code-ReviewFound 27/30 approved changesets -- score normalized to 9
10Contributorsproject has 16 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained18 commit(s) and 10 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
Dependencias directas 17
RegistroPaqueteRestricción de versiónManifiesto
PyPIbeartype>=0.18pyproject.toml
PyPIdags>=0.6pyproject.toml
PyPIipywidgetspyproject.toml
PyPIjaxtyping>=0.3.10pyproject.toml
PyPIkaleido>=1.1pyproject.toml
PyPInetworkx>=3.5pyproject.toml
PyPInumpypyproject.toml
PyPInumpy-groupiespyproject.toml
PyPIopenpyxlpyproject.toml
PyPIoptree>=0.16pyproject.toml
PyPIpandas>=3pyproject.toml
PyPIplotly>=6.5pyproject.toml
PyPIportionpyproject.toml
PyPIpygmentspyproject.toml
PyPIpygraphvizpyproject.toml
PyPIpytestpyproject.toml
PyPIpyyamlpyproject.toml
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

Avisos de dependencias 0

Instalar pypi:ttsim-backend@1.2.1 arrastra 49 paquetes, directos y transitivos: 0 tienen avisos conocidos, de los cuales 0 son dependencias directas.

Ningún aviso conocido afecta a las dependencias evaluadas.

Un aviso significa que la versión registrada en el grafo de dependencias cae dentro del rango afectado de un aviso. No se analiza la alcanzabilidad, y el grafo incluye fijaciones de desarrollo y prueba: un hallazgo puede referirse al utillaje y no al software distribuido.

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 57157,
      "has_wiki": false,
      "homepage": "https://gettsim.readthedocs.io/",
      "languages": {
        "Python": 1005595,
        "Jupyter Notebook": 2152
      },
      "pushed_at": "2026-07-26T09:26:24Z",
      "created_at": "2025-07-24T07:06:26Z",
      "owner_type": "Organization",
      "updated_at": "2026-06-24T18:20:06Z",
      "description": "The computing engine powering GETTSIM",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "AGPL-3.0",
      "default_branch": "main",
      "license_spdx_raw": "AGPL-3.0",
      "primary_language": "Python",
      "significant_languages": [
        "Python"
      ]
    },
    "owner": {
      "blog": "https://gettsim.readthedocs.io/",
      "name": "Taxes & Transfers SIMulators",
      "type": "Organization",
      "login": "ttsim-dev",
      "company": null,
      "location": null,
      "followers": 6,
      "avatar_url": "https://avatars.githubusercontent.com/u/200745588?v=4",
      "created_at": "2025-02-25T09:09:59Z",
      "is_verified": null,
      "public_repos": 7,
      "account_age_days": 516
    },
    "license": {
      "state": "standard",
      "spdx_id": "AGPL-3.0",
      "raw_spdx": "AGPL-3.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.2.1",
          "kind": "patch",
          "published_at": "2026-05-25T11:01:22Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2026-03-19T14:45:04Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2026-01-12T14:31:22Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2025-08-26T09:52:01Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2025-08-09T18:59:40Z"
        },
        {
          "tag": "v1.0a4",
          "kind": "other",
          "published_at": "2025-08-09T06:10:04Z"
        },
        {
          "tag": "v1.0a3",
          "kind": "other",
          "published_at": "2025-07-27T13:52:14Z"
        },
        {
          "tag": "v1.0a2",
          "kind": "other",
          "published_at": "2025-07-26T11:24:26Z"
        },
        {
          "tag": "v1.0a1",
          "kind": "other",
          "published_at": "2025-07-24T14:05:31Z"
        },
        {
          "tag": "v1.0a",
          "kind": "other",
          "published_at": "2025-07-24T13:53:03Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "0fdc84b1753d52b3a35015a966dcb250d98c39aa",
          "body": "`.ai-instructions` + prek-hook bump, plus the code changes ty `0.0.52`\nrequires.\n\n- `.ai-instructions` submodule → `68dc3f4`\n- prek hooks refreshed (ruff `v0.15.19`, pyproject-fmt `v2.25.0`, ty\n`v0.0.52`)\n- ty 0.0.52 fixes: `tt/vectorization.py` and\n  `interface_dag_elements/policy_environment.py`\n-\n[…]\nstays at `v0.0.52` — the latest **published** ty binary (the\n`ty-pre-commit`\n`v0.0.53` tag has no corresponding `astral-sh/ty` release).\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)",
          "is_bot": false,
          "headline": "Bump .ai-instructions to 68dc3f4 + adapt to ty 0.0.52 (#135)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-24T18:20:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b86b0d6e66d7ffaf1002b093fa8ea70f0a0e862e",
          "body": "…k (#133)\n\n## Summary\n\nty now runs only as pre-commit hooks, under both backends, replacing the\ndedicated pixi `type-checking`/`type-checking-jax` features,\nenvironments, and tasks (`pixi run ty` / `pixi run ty-jax` no longer\nexist).\n\n- **numpy run**: the official\n[astral-sh/ty-pre-commit](https://g\n[…]\nsed, 42\nskipped\n- [x] `pixi lock` — lock file validates after pruning\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Replace hand-written ty machinery with the official ty-pre-commit hoo…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-15T19:04:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "cc271726d91192997e2dd090c47bd585c168e2e5",
          "body": "### What problem do you want to solve?\n\nSome guards are used in GETTSIM but not here. Added examples to METTSIM\nand the corresponding ignores to pyproject.toml.",
          "is_bot": false,
          "headline": "Restore PLR vectorization guard (#132)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-06-09T12:37:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fceea5e64202bcbf15bfec05b75e6939da419dc3",
          "body": "…with_original_p_ids (#131)\n\nCloses #130.\n\n- Split `raw_results.columns` into\n`raw_results.columns_with_internal_p_ids` (computable from\n`processed_data` alone, endogenous `p_id_*` columns hold internal\nindices) and `raw_results.columns_with_original_p_ids` (the\nreverse-translation from #108, consum\n[…]\ned with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Split raw_results.columns into columns_with_internal_p_ids / columns_…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-06-07T11:57:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "280694713774da873f7073a6df0012d064e0e1b0",
          "body": "…tsim (#129)\n\nThree related changes, following the discovery in\nhttps://github.com/ttsim-dev/gettsim/pull/1178#discussion_r3366916727\nthat the vectorizer handles ternary expressions (`ast.IfExp` →\n`xnp.where` via `_ifexp_to_call`):\n\n1. **Remove the dead SIM108 ignore** for\n`src_mettsim/mettsim/middl\n[…]\nweep for gettsim's policy code: ttsim-dev/gettsim#1195.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Remove dead SIM108 ignore for middle_earth; showcase ternaries in met…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-06-07T09:15:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ad3d21c122e1f73184f0113d602e7b73e4b30119",
          "body": "…#127)\n\n`load_policy_cases` in `test_mettsim.py` resolved the policy-cases root\nas `ROOT_PATH.parent / \"tests_middle_earth\" / \"policy_cases\"`, i.e.\n`src_mettsim/mettsim/tests_middle_earth/...`, which does not exist. The\nglob found nothing, `POLICY_TEST_IDS_AND_CASES` was empty, and\n`test_policy_case\n[…]\n` — 32\npassed (24 policy cases now collected and green)\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix mettsim policy-case collection: all cases were silently skipped (…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-06-06T07:26:55Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dfc457df33e58d767706eec3c9ae880c12750f22",
          "body": "## Summary\n\nSweep: every call to a project-defined function/method/class with 2+\npositional args is rewritten to use keyword names.\n\nScope:\n- src/ttsim, tests, src_mettsim\n- Project-internal targets only — stdlib, numpy, pandas, jax, and other\nthird-party calls are left alone.\n- The resolver works p\n[…]\ner <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "chore: keyword args for project-internal multi-arg calls (#114)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-03T14:10:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "eb304073b23c73a59dc61af5eff61ff2fa3bcb38",
          "body": "## Summary\n\nFill in the six `*_by_p_id` aggregation primitives that were previously\n`raise NotImplementedError` in both `ttsim/tt/aggregation_numpy.py` and\n`ttsim/tt/aggregation_jax.py`. `sum_by_p_id` was the only kind\nimplemented before; everything else surfaced as `NotImplementedError` to\ncallers.\n[…]\ner <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Implement count/mean/max/min/any/all by_p_id aggregations (#110)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-03T14:06:49Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4351a458eb5ba1f1302a043540f57e20c6ec3cd9",
          "body": "…) (#108)\n\n## Summary\n- `raw_results.columns` now reverse-translates any output column whose\nleaf name starts with `p_id_` from internal indices back to user-space\n`p_id` values, preserving the `-1` no-link sentinel.\n- Removes the previously protective\n`fail_if.endogenous_p_id_among_targets` (and it\n[…]\ner <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Reverse-translate endogenous p_id_* targets to user p_ids (closes #43…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-03T14:03:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "7d7530ac3c23777d64921248fd5b8a1047eeb77c",
          "body": "…s (#113)\n\n## What\n\nScalar inputs feeding functions that are **not** auto-vectorized —\naggregations, group-creation functions, and\n`vectorization_strategy=\"not_required\"` policy functions — are now\nbroadcast to length `n_obs` at **call time**, instead of raising a\nfail-fast error. Auto-vectorized fu\n[…]\n.7 <noreply@anthropic.com>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Defer scalar→array broadcast to call time for non-vectorized function…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-06-02T17:02:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b781ec81523c8114192eb3edad794d7eaf69e49f",
          "body": "## Summary\n- Closes #84.\n- Expands the module docstring in ``src/ttsim/typing.py`` to capture why\n``TYPE_CHECKING`` + ``from __future__ import annotations`` must stay in\nplace across the codebase: ``jaxtyping.Array`` resolves via a top-level\n``__getattr__`` hook that imports JAX, so any module touch\n[…]\nuthored-by: Claude Opus 4.7 <noreply@anthropic.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Document JAX-optional constraint on typing module (#84) (#106)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-02T16:14:27Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a4cc9c5e0cb87104fb3b61150f08a86a13290d23",
          "body": "…105)\n\n## Summary\n- Closes #73.\n- Cause: ``load_module`` registered policy modules in ``sys.modules``\nunder a *root-relative* short name (e.g.\n``orc_hunting_bounty.orc_hunting_bounty``). Decorated objects'\n``__module__`` then pointed at a non-importable name, so cloudpickle's\npickle-by-reference mac\n[…]\nuthored-by: Claude Opus 4.7 <noreply@anthropic.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Load policy modules under their canonical Python import name (#73) (#…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-02T16:09:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ca81551cc6ffe6e64760f092386fd99f6c1f1247",
          "body": "…79) (#104)\n\n## Summary\n- Closes #79.\n- ``with_processed_params_and_scalars``\n(``specialized_environment.py:152``) used to only insert scalars from\n``processed_data`` when the qname was already a key in\n``without_tree_logic_and_with_derived_functions``. The time-conversion\nmachinery builds conversio\n[…]\nuthored-by: Claude Opus 4.7 <noreply@anthropic.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Partial scalar inputs that drive derived time-conversion functions (#…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-02T16:04:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "368cdf3ef458a83edbbb98e6aac7114c67fa0827",
          "body": "## Summary\n\nMirror `results.df_with_qname_columns` with the input-side counterpart\nso the qname format works in both directions.\n\n- `InputData.qname({\"a__b\": ...})` becomes a live factory. Previously\nthe factory existed in the public API but no interface function consumed\n`input_data__qname`, so cal\n[…]\nuthored-by: Claude Opus 4.7 <noreply@anthropic.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Add symmetric qname I/O for InputData and results (#103)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-02T15:59:54Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "747bd3eeec944db5e5315a145f0a17024c57fd32",
          "body": "…loses #97, #94) (#102)\n\n## Summary\n\nA single ``_canonicalize_input_dtype`` helper in ``processed_data.py``\nnow normalizes every kind of non-canonical input column to numpy:\n\n- **Unsigned integers** (numpy uint, pandas-nullable ``UInt*``,\n``uint*[pyarrow]``) → ``int64`` (``int32`` on jax with x64 di\n[…]\nuthored-by: Claude Opus 4.7 <noreply@anthropic.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Canonicalize input dtypes; coerce uint, normalize nullable/pyarrow (c…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-02T15:55:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0fabd06c89aa6c928df5ca3a7f361e69e306da15",
          "body": "Implements GEP 9: package-wide beartype claw on by default, TTSIM_BEARTYPE_CLAW=0 as a full opt-out (O0-strategy confs gate perimeter decorators + forwarder), TTSIMError hierarchy, wide/narrow UserX type split. See PR #101.",
          "is_bot": false,
          "headline": "Beartype + jaxtyping runtime type-checking rollout (GEP 9) (#101)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-06-02T15:15:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4d02ac8665f2220053a583e0ea40a3a0351065c3",
          "body": "Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Prepare release 1.2.1 (#112)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-05-25T10:58:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c30f66d24c84bf4106ceb753cd0f47e95a054964",
          "body": "## Coordinated change\n\nPart of a three-repo change adopting runtime type checking in dags-based\nprojects:\n\n-\n**[OpenSourceEconomics/dags#82](https://github.com/OpenSourceEconomics/dags/pull/82)**\n— makes dags wrappers honest forwarders so runtime checkers aren't\nmisled. Keystone; releases as dags 0.\n[…]\nlf. The forward-compatible half\nis exercised by dags#82's own suite.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.7 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Adapt to dags' runtime-type-checker-friendly wrappers (#99)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-05-24T10:03:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8ecbaca5462925442afe795e67408a355266e9cb",
          "body": "## Summary\n\nVectorisation strategy `\"loop\"` failed if functions had piecewise\npolynomial param inputs. This PR fixes this.\n\nRelated to #91 — these fixes enable downstream projects (e.g. GETTSIM)\nto switch policy functions to the `\"loop\"` strategy for any (not already\nnatively) vectorised function.\n\n\n[…]\n resolve type\nannotations on `numpy.vectorize` objects.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix loop vectorization for functions with param helpers (#92)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-03-23T15:11:35Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6fd0123d160a1e32604b71f8e3141c8b87c76872",
          "body": null,
          "is_bot": false,
          "headline": "Change title in changelog for release.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-03-19T14:40:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5cf4228eb23912616f52f05160a78a495af60160",
          "body": null,
          "is_bot": false,
          "headline": "Prepare CHANGES.md for release.",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-03-19T14:25:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "61ef297df75fa69ff6c7b8ad9ecc514324546f35",
          "body": "- make a dataclass frozen\n- add dags.md to ai-instructions\n- bump pyproject-fmt and apply",
          "is_bot": false,
          "headline": "Trivial updates to code quality. (#90)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-03-19T14:09:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c17c1f5ff36cb5d4ca924dfbf336ef1ee3ae62f",
          "body": "## Summary\n- Convert all NumPy-style `Parameters`/`Returns`/`Raises` docstring\nsections to Google convention across 15 infrastructure files\n- Drop type annotations from docstrings (already in signatures)\n- Net: -182 lines (more concise format)\n\nCloses #88\n\n## Test plan\n- [x] `pixi run ty` — all chec\n[…]\nGenerated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "Migrate docstrings from NumPy to Google convention (#89)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-03-19T11:08:46Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9bbba34d26703f5f8febffaa2ff7d4d8397f44ed",
          "body": "…08) (#76)\n\nImplemt GEP-08.\n\nReplace numbered dict format with ordered list of interval dicts:\n- Add interval_utils.py: validate_intervals(),\nextend_intervals_to_real_line()\n- Support partial domains (NaN for out-of-domain values)\n- Transpose rates shape from (n_coefficients, n_intervals) to\n(n_inte\n[…]\nuthored-by: Claude Opus 4.5 <noreply@anthropic.com>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "Refactor piecewise polynomial to use explicit interval notation (GEP-…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-03-19T05:46:08Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9e2aad237bf7da831db576b1cc1cef6fa20a9b3a",
          "body": "`dags` 0.5.0 includes a couple of changes, which would raise\n`DeprecationWarning`s and at some point break `ttsim`:\n\n- `fail_if_paths_are_invalid` has been removed from `dags.tree`\nnamespace, must import via `from dags.tree.validation import\nfail_if_paths_are_invalid`\n- `one_function_without_tree_logic` has been renamed to\n`get_one_function_without_tree_logic`\n\nWe fix those imports here.",
          "is_bot": false,
          "headline": "Require `dags` 0.5.0 (#86)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-03-11T10:08:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "100477aa33a0915fd919f3776b3a537e705285fe",
          "body": "### What problem do you want to solve?\n\nInternally, we need string annotations (via `from __future__ import\nannotations`) and `if TYPE_CHECKING` blocks in order to not require jax\nas a runtime dependency:\n\n- Bool, Float, Int (dtype validators) can be imported without JAX\n- Array cannot - it triggers\n[…]\nrization machinery. Changing two lines helps.\n\n---------\n\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>\nCo-authored-by: Marvin Immesberger <74215010+MImmesberger@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Allow non-string annotations in vectorization. (#83)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-02-12T18:25:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fd099009d29b78670c92923435d324becb515983",
          "body": "## Summary\n- Add a `run-ty` job to the main CI workflow that runs the `ty` static\ntype checker\n- Runs on `ubuntu-latest` using the `py314-jax` pixi environment, in\nparallel with existing test jobs\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n---------\n\nCo-authored-by: Claude Opus 4.6 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add ty static type checker to CI (#82)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-02-12T18:07:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e647ffe16f221ecd438d212d943bb095e6922c75",
          "body": "### What problem do you want to solve?\n\nCloses #18 \n\n- Add extensive test coverage for interface layer modules\n- test_interface_node_objects.py - Tests for interface DAG node objects\n- test_dates.py - Tests for date handling functionality\n- test_labels.py - Extended label tests\n- test_tt_targets.py \n[…]\n.5 <noreply@anthropic.com>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Improve test coverage (#75)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-02-12T10:46:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0397cba2c5798215db3f14442f3c149673cb6416",
          "body": "Fix #80.\n\n*(curse of dimensionality at work, sorry...)*\n\n---------\n\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "Generalise type hints of time conversion functions (#81)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-02-11T21:23:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d36b549d83731bcb0a4d145f6fc48027101a6a1b",
          "body": "Move ty to test feature and other updates following the new template.\n\n---------\n\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Boilerplate update (#74)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2026-01-28T10:45:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2e26d3ff97725d593db9641f9b9b1ddd0349384d",
          "body": "- Ran\n[code-simplifier](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/code-simplifier)\non the codebase.\n- Use `pyproject.toml` etc. based on https://github.com/OpenSourceEconomics/ai-instructions/tree/main/boilerplate\n\n---------\n\nCo-authored-by: Marvin Immesberger <74215010+MImmesberger@users.noreply.github.com>\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "Simplify, update boilerplate code (#69)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-01-23T16:56:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eef66a63166c0b3478489f102b68863f0af8968c",
          "body": "Fix #58",
          "is_bot": false,
          "headline": "Get rid of UnitTest style tests. (#68)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-01-21T13:37:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "51f3d8d5de6e7751664339fa3d6376a22f2bd55b",
          "body": "Fix #45 using standard glob patterns:\n\n| Pattern element | Meaning |\n|-----------------|---------|\n| `\"exact_name\"` | Matches this exact path segment |\n| `\"prefix*\"` | Matches segments starting with `prefix` |\n| `\"*suffix\"` | Matches segments ending with `suffix` |\n| `\"*infix*\"` | Matches segments c\n[…]\n](https://gettsim--1128.org.readthedocs.build/en/1128/tutorials/visualizing_the_system.html#Glob-patterns-for-flexible-matching).\n- Twin [GETTSIM #1128](https://github.com/ttsim-dev/gettsim/pull/1128)",
          "is_bot": false,
          "headline": "Better selection mechanism for `node.colormap` in graphs. (#67)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-01-18T08:08:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0768ada5a637472912a242cd9c09ee75e9c2eb13",
          "body": "Requires a fix on the dags side in 0.4.2 (see [dags #59](https://github.com/OpenSourceEconomics/dags/pull/59) that popped up in GETTSIM, add a reproducer here.\n\n---------\n\nCo-authored-by: Claude Opus 4.5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add Python 3.14 support. (#65)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2026-01-08T17:58:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8a07b104230a0e4eefa481fe70eb67e781f12791",
          "body": "Lots of improvements, highlights:\n\n- The typing of `OrigParamSpec` was off. What we had written was \"one of\ntwo exclusive kinds of dictionaries\" where we wanted to write \"One\ndictionaries where key/value pairs can take one of two forms\". Fixed via\na Protocol.\n- Use `TypeAlias` for `OrderedQNames` in\n[…]\nsted_nodes_cannot_be_found` to \n`_fail_if_requested_nodes_not_in_dag` and do not do redundant check on\ninput-dependent interface functions (made a test out of that).\n\n---\n- co-authoed by @MImmesberger",
          "is_bot": false,
          "headline": "Move from mypy to ty (#63)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-12-23T14:25:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9c7c7f736d4c8a0bad208be8e77e640b9b4d9cba",
          "body": "- Update pixi in GHA.\n- Wrap parsing of options in try-except block so we can run tests in all repos included in dev-gettsim workspace.",
          "is_bot": false,
          "headline": "Some chores (#62)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-12-21T09:22:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "855816a0babe1ebbc90b629f97bb8b07f040dba5",
          "body": "<!--pre-commit.ci start-->\nupdates:\n- [github.com/lyz-code/yamlfix: 1.17.0 →\n1.19.0](https://github.com/lyz-code/yamlfix/compare/1.17.0...1.19.0)\n- [github.com/astral-sh/ruff-pre-commit: v0.12.11 →\nv0.14.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.11...v0.14.7)\n- [github.com/kynan/\n[…]\n0.35.0)\n<!--pre-commit.ci end-->\n\n---------\n\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": true,
          "headline": "[pre-commit.ci] pre-commit autoupdate (#59)",
          "author_name": "pre-commit-ci[bot]",
          "author_login": "pre-commit-ci[bot]",
          "committed_at": "2025-12-16T13:03:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b1bd853bcc388387813643cda900d36e80b15fc9",
          "body": "Bumps the github-actions group with 3 updates in the / directory:\n[actions/checkout](https://github.com/actions/checkout),\n[prefix-dev/setup-pixi](https://github.com/prefix-dev/setup-pixi) and\n[actions/setup-python](https://github.com/actions/setup-python).\n\nUpdates `actions/checkout` from 5 to 6\n<d\n[…]\n of the specified dependency and ignore\nconditions\n\n\n</details>\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump the github-actions group across 1 directory with 3 updates (#61)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2025-12-16T11:49:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6d3482c1429f0529a709d65badfcb48ca3c5eb67",
          "body": "### What problem do you want to solve?\n\nThis PR\n- renames time converters for flow variables (e.g. earnings **per**\nmonth) from `x_to_y` to `per_x_to_per_y` with x, y being our usual time\nabbreviations.\n- adds time converters for stock variables (e.g. number of unemployment\nperiods on the monthly **level**) named `x_to_y`\n- exposes the stock time converters to make them importable via\n`ttsim.interface_dag_elements`.",
          "is_bot": false,
          "headline": "Add and expose time converters targeting stocks (#56)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-10-02T07:53:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "755304bcde926bef7b12f9a8bea8573450d04fb8",
          "body": "### What problem do you want to solve?\n\nThe _q to _m automatic time conversion (and the corresponding test) was\nincorrect. This PR fixes that.",
          "is_bot": false,
          "headline": "Fix _q to _m time conversion. (#55)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-09-15T07:50:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "305f4f8d003b14e6781b7a96f0e7d8aa3d60d6af",
          "body": "### What problem do you want to solve?\n\nAdds\n\n- a `fail_if` function that raises an error if a function expects an\narray as an input (because it is natively vectorized), but got passed a\nscalar via `processed_data`\n- a `warn_if` function that raises a warning if\n`tt_function_set_annotations` is `False` (because this disables the\ncheck above).\n\n---------\n\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Raise error if scalar is passed to function expecting an array (#53)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-09-06T15:07:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "591358e1baa7ac950a4ab00da64c35b30ef47a14",
          "body": "…d an ambiguous name. (#52)\n\n### What problem do you want to solve?\n\n- `fail_if__input_data_tree_is_invalid` was too strict because it\nallowed for array leafs only. It now also allows for float/int/bool.\nAlso fixed some corresponding bugs down the line.\n- Rename `environment_is_invalid` to `policy_environment_is_invalid` to\nmake clear that this is not about the specialized policy environment.\n\n---------\n\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Fix fail_if checks: input data tree was too greedy and environment ha…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-09-04T12:25:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5d8a6ebf7640ad8dc1a5b289e6e02f476d42a56",
          "body": "Bumps the github-actions group with 2 updates:\n[actions/checkout](https://github.com/actions/checkout) and\n[prefix-dev/setup-pixi](https://github.com/prefix-dev/setup-pixi).\n\nUpdates `actions/checkout` from 4 to 5\n<details>\n<summary>Release notes</summary>\n<p><em>Sourced from <a\nhref=\"https://github\n[…]\n of the specified dependency and ignore\nconditions\n\n\n</details>\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump the github-actions group with 2 updates (#50)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2025-09-01T07:24:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b08f2e1f61badf375f9d3711a595db927b39e5df",
          "body": null,
          "is_bot": false,
          "headline": "Typo spotted by @JuergenWiemers",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-08-26T16:34:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1fda301ebd80577187e2ec1eeb3360707f9699c1",
          "body": "Closes #47",
          "is_bot": false,
          "headline": "Fix test failure on WSL2 due to different DAG execution order (#49)",
          "author_name": "JuergenWiemers",
          "author_login": "JuergenWiemers",
          "committed_at": "2025-08-26T16:20:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6404bd3ff65e8ed934a93daf9d7e58209265f092",
          "body": "Just updated the heading for v1.1.0",
          "is_bot": false,
          "headline": "Fix changelog ex post. (#48)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-08-26T09:54:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d0942d8f25fbd2dc5f97b6007796e95147d2b13c",
          "body": "### What problem do you want to solve?\n\nSee discussion in [GETTSIM\n#1073](https://github.com/ttsim-dev/gettsim/issues/1073). Currently, the\ncycler will pick different colors for nodes depending on the contents of\ngraph.\n\nThis PR allows specifying a mapping of tree paths to colours in both\n`plot.dag`\n[…]\nupsert_tree` and `merge_trees`.\n- Re-ordered the arguments to 'main' into blocks: [typical user input]\n[rough interface dag flow]\n\n---------\n\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "Plots with colormap and improved descriptions (#44)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-08-26T09:45:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "788b727a40da7bf8aadc9803cd6693e87d62334a",
          "body": "Small optimization. Considerable impact if `include_fail_nodes=True` and\nthe input data is large.",
          "is_bot": false,
          "headline": "Optimization for `fail_if.foreign_keys_are_invalid_in_data` (#46)",
          "author_name": "JuergenWiemers",
          "author_login": "JuergenWiemers",
          "committed_at": "2025-08-21T16:51:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "83de7f68f1acd62bcaf6b920b49864edd48b616c",
          "body": "This PR pre-sorts user data by original person ID (`p_id`) to improve\nperformance.\n\n### Key Changes:\n\n- User data is now sorted by original `p_id` early in the pipeline\n(`processed_data`)\n- Introduced a new `sort_indices` interface function that computes\nsorting indices for restoring original row or\n[…]\ner endogenously computed\n`p_id`s are included in the target list, opened #43 related to that\n- Added tests for row order restoration functionality\n- Updated existing tests to work with the sorted data",
          "is_bot": false,
          "headline": "Pre-sort user data by p_id for performance (#42)",
          "author_name": "JuergenWiemers",
          "author_login": "JuergenWiemers",
          "committed_at": "2025-08-20T08:21:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8d88fa76958e76c8402840d628045c915a0e343d",
          "body": "…s.fail_if` functions (#41)\n\n- The crucial change is in `tt.shared.join`. It looks like we currently\nuse an NxN lookup table; we really shouldn't do that. 😅With this PR,\nruntime complexity is $O(log(n))$ instead of $O(n)$ and memory usage is\n$O(n)$ instead of $O(n^2)$.\n- The optimizations in the `fail_if` functions mostly help the\n\"pre-processing stage\".",
          "is_bot": false,
          "headline": "Optimizations: `tt.shared.join`, several `ttsim.interface_dag_element…",
          "author_name": "JuergenWiemers",
          "author_login": "JuergenWiemers",
          "committed_at": "2025-08-14T08:12:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ad625be4b02aad01e7ffacbacbf09dfec85589a3",
          "body": "Optimize `aggregation_numpy.sum_by_p_id` and small optimization of\n`data_converters.df_with_mapped_columns_to_flat_data`\n\n- I am still trying to pick some low hanging (optimization) fruits. I am\nreaching the point of diminishing returns (which is good!).\n- I tried to be minimally invasive. I only re\n[…]\n7     1.22x       Complete execution                   \n--------------------------------------------------------------------------------------------------------------------------------------------\n```",
          "is_bot": false,
          "headline": "Improve performance of `aggregation_numpy` and `data_converters` (#40)",
          "author_name": "JuergenWiemers",
          "author_login": "JuergenWiemers",
          "committed_at": "2025-08-12T05:15:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "97dea8a9add9dd8218c5f8c494b388c150d9b7f7",
          "body": "### What problem do you want to solve?\n\nThe `all_paths` selection type shows all paths that connect any primary\nnodes. There must be at least two primary nodes.",
          "is_bot": false,
          "headline": "Plotting: Replace `nodes` selection type with `all_paths` (#38)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-08-09T18:54:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bae8342b06708de6fcbf88602bffaf4ebea5bedb",
          "body": "### What problem do you want to solve?\n\nCloses #33\n\nAlso adds `SpecializedEnvironmentForPlottingAndTemplates` as an argument\nto `main`.\n\n---------\n\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
          "is_bot": false,
          "headline": "Pass all arguments of main via class methods (#37)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-08-09T14:48:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "355e17769378ab17b69dac838ccad3e9cdd094e6",
          "body": null,
          "is_bot": false,
          "headline": "Fix (?) security permissions for GHA workflow. (#36)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-08-09T06:08:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5cebf9a184eeeacb70672a9717f595801c5583fe",
          "body": "…lisher set up) (#35)",
          "is_bot": false,
          "headline": "Remove token from publish-to-pypi (counterproductive with trusted pub…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-08-09T05:53:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "18bbce2bc54ce74410338b37274374e70ad90cc7",
          "body": "…ased on `policy_input`s (#32)\n\n### What problem do you want to solve?\n\nCloses #27, #30, #24\n\nThis PR fixes the root problem of many issues we had with the\ncreation of templates and plotting: derived functions are part of the\n`specialized_environment` only if they can be build from input data or\noth\n[…]\n53113+pre-commit-ci[bot]@users.noreply.github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Build inputs template and plotting DAG from specialized environment b…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-08-09T05:32:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "57cc3536b3a4df5360d6d7eba9178769d32b2020",
          "body": "- Improve speed of pandas -> jax array conversion by going via numpy.\n- Improve duplicate detection algorithm.\n- Speed improvement is more than 12-fold in some cases.",
          "is_bot": false,
          "headline": "Optimize JAX performance in data preparation pipeline (#34)",
          "author_name": "JuergenWiemers",
          "author_login": "JuergenWiemers",
          "committed_at": "2025-08-08T15:08:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c69ccd08d0002b496029d5d9934ae61f442d1b77",
          "body": "### What problem do you want to solve?\n\nThe TT DAG has orphan nodes when not selecting a target via\n`NodeSelector`.\n\n- Those nodes are: `evaluation_x`, `policy_x` for `x \\in [\"year\",\n\"month\", \"day\", \"date\"]`\n- They are part of the DAG because they are `policy_inputs`\n- They are orphaned if they are \n[…]\nnction`s\n(in GETTSIM), not `policy_function`s.\n\nIf this is the case, this PR removes the explicitly from the plotting\nDAG.\n\n---------\n\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Remove orphaned nodes from tt dag (#23)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-08-01T06:58:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "23bfd12dd05b0b8d38195f6c207f777ade3afceb",
          "body": "- Move `mettsim` into its own folder and package, which mirrors the\nstructure of `gettsim` in that it has subfolders `middle_earth` and\n`tests_middle_earth`.\n- Use imported `middle_earth.ROOT_PATH` instead of `METTSIM_ROOT`s\ndefined in dozens of files.\n- [unrelated] In `./pyproject.toml`, use `hatch-vcs` instead of\n`hatch_vcs` since conda linter complained.",
          "is_bot": false,
          "headline": "Improve \"packaging\" of METTSIM (#22)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-28T08:43:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e5efdbb9950f46341c432eef1adb0c34d467d11d",
          "body": null,
          "is_bot": false,
          "headline": "Fix changelog. (#21)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-27T13:51:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a53ba806ceaa08956943586086eb44ca5943f321",
          "body": "Mostly motivated by a corresponding GETTSIM PR, this does the following:\n\n- Rename the `mettsim` / `mettsim_tests` directories to `middle_earth`\nand `tests_middle_earth`\n- Rename the `test_data` directory to `policy_cases` and adjust function\nnames.",
          "is_bot": false,
          "headline": "Clearer architecture (#19)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-27T13:37:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "87227c2cd1d00cb7eeda18163266576f9153399d",
          "body": "### What problem do you want to solve?\n\nAdds the param type `sparse_to_consecutive_int_lookup_table` alongside\nof `convert_sparse_to_consecutive_int_lookup_table`.\n\n---------\n\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Add type for sparse dict with integer keys param (#17)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-27T07:08:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ee64da3a99454ec087814678906217fbdbc6ae2",
          "body": "- As discussed in [GETTSIM\n#1055](https://github.com/ttsim-dev/gettsim/pull/1055), we sometimes\nwant to fail or issue a warning if a certain node is visited in the\ngraph. This PR adds a mechanism for that along with corresponding tests\n- Implementation: \n  - All `ColumnObjects` and `ParamFunctions` \n[…]\ned that `tt_dag` is a better name\nfor `tax_transfer_dag` as we are using that abbreviation much more\nextensively that 'tax_transfer' by now. Renamed, same for\n`tax_transfer_function` -> `tt_function`.",
          "is_bot": false,
          "headline": "Add fail/warn mechanism to ColumnObjects and ParamFunctions (#16)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-26T11:08:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4d049b1b3a97089c2aad00cb98165e4d0964bb28",
          "body": "Fix another GETTSIM test failure with Jax 0.7.0.\n\nAdd test and fix.",
          "is_bot": false,
          "headline": "Do not call len() on unsized arrays (#15)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-26T05:00:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cbf0e4c5c810a77618fcab90d9b480adc9335fef",
          "body": "…_changed' (#14)\n\nDoing so yields an error with Jax 0.7.0",
          "is_bot": false,
          "headline": "Do not loop over the attributes of Jax arrays in 'fail_if.backend_has…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-26T04:16:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d9a098b45dbe96f90330c67b8b6587427ae62b8",
          "body": "### What problem do you want to solve?\n\nAs suggested\n[here](https://github.com/ttsim-dev/gettsim/pull/1056#pullrequestreview-3056621461).\n\n---------\n\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Put plotting functions in `ttsim.plot.dag` namespace (#13)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-26T03:57:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "58818e63bd807672c095bc8ec7661039f5fd89a4",
          "body": "### What problem do you want to solve?\n\nI tried both versions (with/without fail nodes) using GETTSIM's tests\nwith the py13 environment and backend numpy. 52 vs 53 seconds, so should\nbe no big deal turning it on.",
          "is_bot": false,
          "headline": "Turn on `fail_if` nodes when running policy tests (#12)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-25T19:47:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9fb394ccdc83a733b17d012f85d92c91831c4910",
          "body": "### What problem do you want to solve?\n\n@JuergenWiemers pointed out that some nodes are missing when calling\n`plot_tt_dag`.\n\nIt turned out that there were two bugs:\n1. When using `NodeSelector`, we didn't add the \"main\" node to the DAG\n(`nx` doesn't do so automatically)\n2. We still had an `include_o\n[…]\ntion of `evaluation_x`, `policy_x`, `xnp`,\n`dnp` and friends. This caused `policy_inputs` and some other nodes to\nbe thrown out of the DAG. I removed the argument completely, we don't\nneed it anymore.",
          "is_bot": false,
          "headline": "Fix several bugs in `plot_tt_dag` (#11)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-25T19:21:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "44a38d263aee7fd23bda0e694d4179b4eed35de9",
          "body": "### What problem do you want to solve?\n\n- Fix #4 \n- Had to change quite a few tests which should have failed for other\nreasons, but where this error came first now.\n- Update pixi on GHA\n\n---------\n\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "Raise error when passing data but no targets (#9)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-25T17:33:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e10fd6d189dfed950ac48862e7e1f1a7b7493dba",
          "body": "Closes #7",
          "is_bot": false,
          "headline": "Allow for input data as targets. (#8)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-25T09:33:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8889863fa2f8f66c7b518c2d9180f77bf3d2350d",
          "body": "Fail if the leaf name of an object in the policy environment differs from the last element of the path",
          "is_bot": false,
          "headline": "Merge pull request #6 from ttsim-dev/fail_if_leaf_name_diff",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-25T09:22:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ffa681ef47173c7a4d044974020f06a0fb7d3c35",
          "body": null,
          "is_bot": false,
          "headline": "Fix workflow file, exclude elements need to be atomic.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-25T07:57:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b313688d9c283d9033fa0620a33c1a95ad375a04",
          "body": null,
          "is_bot": false,
          "headline": "Remove leaf name attribute from ParamObjects.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-25T07:55:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "737f684ae962a27d4289126ba2aeca800d8117f6",
          "body": null,
          "is_bot": false,
          "headline": "Don't specify default value to make things easier to read; renamings.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-25T07:25:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "89ea7902c599487c8be28b0a7feb8916a02af203",
          "body": "…eaks that come from formatter).",
          "is_bot": false,
          "headline": "Simplify fail function, correct regex in test (never depend on linebr…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-25T07:24:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "432ad81bf1b26c41d06de48cfc0150a002e7b2b8",
          "body": null,
          "is_bot": false,
          "headline": "Improve error message a bit.",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-24T20:20:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d88a15781ef2355db114c87a9b35b4dbf73869ab",
          "body": null,
          "is_bot": false,
          "headline": "Fail if leaf name is different than last path element.",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-24T20:17:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2ebbfa1a3a2920e16d2cbee5203bc8c4d34de4b9",
          "body": "…me package to ttsim-backend because PyPI decided it was too similar to an existing package.",
          "is_bot": false,
          "headline": "Renamings as described in PR #3 (history was messed up), have to rena…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-24T14:03:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ceb05ca61935fbb1f225addb2e368ed91c6839bd",
          "body": null,
          "is_bot": false,
          "headline": "Initial standalone TTSIM",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-24T10:40:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "22292553e9f00cffeb39f0f1784ccb9796e42c8d",
          "body": null,
          "is_bot": false,
          "headline": "Add mac object to gitignore, wording in question template.",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-24T10:24:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5a9302d6d4b5b98a9b1134fb29b5fe2bc054f4a3",
          "body": "… function.",
          "is_bot": false,
          "headline": "Allow not requiring correct type annotations in the taxes & transfers…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-24T09:20:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "67fae6b21d5d1b301e852702f096bf338061b017",
          "body": null,
          "is_bot": false,
          "headline": "Add comment to params schema file.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-24T09:03:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21f01d5c60209969cf0843957c004adea42149d1",
          "body": null,
          "is_bot": false,
          "headline": "Fix versioning.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-24T08:24:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec7006ddde69ef53aac56ecc78a9abd37fb173ba",
          "body": null,
          "is_bot": false,
          "headline": "Initial shot of removing GETTSIM.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-24T08:11:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ad1d40e347f11a2f15c45cd8a01aaea8b5577097",
          "body": null,
          "is_bot": false,
          "headline": "Remove explicitly adding group ID to template, see issue #1051.",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-23T17:17:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5fe956fc8a8d1c5b9ae55a40d389ea105254b4b9",
          "body": "### What problem do you want to solve?\n\n- [x] Add a GEP for the revamped interface\n- [x] Update earlier GEPs to reflect the changes that have become\nnecessary after GEP 6 (since our documentation is small, it does not\nmake sense to keep outdated things around).\n- [x] Add the finalised schema from #8\n[…]\nppendix to GEP 3\n\n[Resolution on Zulip.](https://gettsim.zulipchat.com/#narrow/channel/309998-GEPs/topic/GEP.2007/near/530389224)\n\n---------\n\nCo-authored-by: Marvin Immesberger <immesberger@posteo.de>",
          "is_bot": false,
          "headline": "GEP 7 and updates to GEPs 1-5 necessitated by GEP 6 (#855)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-23T16:42:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "84daa3c28155261741f363d18d7292bd794f78ab",
          "body": "…omatically created function (#1050)\n\n### What problem do you want to solve?\n\nCloses #1049\n\n---------\n\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Allow input template creation when path to root node traverses an aut…",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-23T16:31:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b88e3e1615af3242dde3b45965b12f4461cf0e22",
          "body": "…994 (#1048)\n\nCheck whether the structure of the paths matches. E.g.:\n\n- `input_data={\"df_and_mapper\": None}`: Fails because there needs to be\na dict below \"df_and_mapper\"\n- `input_data={\"not_around\": None}`: Fails because `not_around` is not a\nvalid child of `input_data`\n- `not_around=None`: Fails because not around is not a valid root node\n(already taken care of by Python itself when calling `main`, but let's\nbe pedantic...)",
          "is_bot": false,
          "headline": "Raise an error if invalid input paths are provided to `main`, fixes #…",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-23T14:23:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "205f3585d90f780cd3794ce0cb813ba5d4d757e2",
          "body": "Add `fail_if.backend_has_changed`. \n\nLessons learned:\n- Numpy can handle Jax arrays (see test)\n- Jax can handle NumPy arrays that are passed as the processed data (see\ntest)\n- The problematic case are parameters that are partialled to functions.\nUnfortunately, these are typically custom objects. We to loop over them and\ncheck whether any of them happens to be a numpy array",
          "is_bot": false,
          "headline": "Fail if backend has changed (#1046)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-23T14:15:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3437b127aee77aba704f97879c3bfa5729db279c",
          "body": "Fixes #869\n\n- Raise an error when type-conversion calls like float, int, etc. are encountered\n- Raise an error when augmented assignment (+= and -= and *= and /= and friends) are encountered\n- Remove some tests that actually relied on that behavior, make test numbering consistent.",
          "is_bot": false,
          "headline": "Raise more errors during vectorization (#1043)",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-23T09:37:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e4e7ada6c81c8829d2aeef07838b2cf5b6b2da63",
          "body": "### What problem do you want to solve?\n\nCloses #999 \n\nFails if any `param_function` depends on a `ColumnObject`, with the\nexception being `evaluation_x` and `policy_x` (they are `PolicyInputs`).\n\n---------\n\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Fail if ParamFunctions depends on ColumnObjects (#1044)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-23T08:12:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30662fa06b8e08612c3a55f2cd68a20de4863567",
          "body": "This reverts commit 6f12a598df1a216d123617b94a9cbb534499f20f.",
          "is_bot": false,
          "headline": "Revert \"Fail if param functions depend on policy functions.\"",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-22T15:45:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6f12a598df1a216d123617b94a9cbb534499f20f",
          "body": null,
          "is_bot": false,
          "headline": "Fail if param functions depend on policy functions.",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-22T15:44:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cbf95c1fddc77955384e41fcdf62007cb256f9f8",
          "body": null,
          "is_bot": false,
          "headline": "Had merged without double-checking all tests...",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-22T13:26:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f3532215a3d3d4827e79bf68e7680a6a42294f1",
          "body": "*Leaving the almost-unedited stuff from Claude Code here for\ndemonstration purposes*\n\n## Summary\n\n- Implements `copy_environment` function to address issue #1008\n- Provides proper copying of policy environments containing unpickleable\nfunction objects\n- Available in both `ttsim` and `gettsim` namesp\n[…]\n--\n\nCo-authored-by: Marvin Immesberger <74215010+MImmesberger@users.noreply.github.com>\nCo-authored-by: Claude <noreply@anthropic.com>\nCo-authored-by: Hans-Martin von Gaudecker <hmgaudecker@gmail.com>",
          "is_bot": false,
          "headline": "Add copy_environment function (#1008) (#1042)",
          "author_name": "Tim Mensinger",
          "author_login": "timmens",
          "committed_at": "2025-07-22T13:01:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6e4f869a52532b35a7745d5d2f14ffdbdf469f0e",
          "body": "### What problem do you want to solve?\n\nCloses #757\n\nIn fact, any occurences of automatically created cycles reported in #757\nhave already been solved via the namespaces structure.\n\nIn ALG2 we have\n\n```python\n@policy_function(start_date=\"2005-01-01\")\ndef wohnfläche(\n    wohnen__wohnfläche_hh: float,\n[…]\nrbeitslosengeld_2__wohnfläche`.\n\nStill, thanks to the work done by Lars in the past, a general TTSIM\nsolution was easy to implement because it just copies the logic done for\ntime-conversion functions.",
          "is_bot": false,
          "headline": "Don't create DAG cycles via automatically added functions (#1041)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-22T12:46:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c4946933cb4073e73d33d47884fcc04a2e1e060e",
          "body": null,
          "is_bot": false,
          "headline": "Fix links, formatting, add 1041.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-22T10:32:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "395a7875311971d498491d5584c6907efa551f21",
          "body": null,
          "is_bot": false,
          "headline": "Fix links.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-22T09:58:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ef80ca67f125e29adb1d963eb0dc0025fdcd995",
          "body": null,
          "is_bot": false,
          "headline": "Update changelog.",
          "author_name": "Hans-Martin von Gaudecker",
          "author_login": "hmgaudecker",
          "committed_at": "2025-07-22T09:52:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "43279825e47409637e75a6b2ccc9f7214b9dc25f",
          "body": "### What problem do you want to solve?\n\nThis PR gets the input names (+docstrings) of \"vorjahr\" and similar inputs straight\nand puts them in the correct namespaces.",
          "is_bot": false,
          "headline": "Vorjahr input names and their namespaces (#1040)",
          "author_name": "Marvin Immesberger",
          "author_login": "MImmesberger",
          "committed_at": "2025-07-22T09:51:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 10,
      "commits_last_year": 62,
      "latest_release_at": "2026-05-25T11:01:22Z",
      "latest_release_tag": "v1.2.1",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 22,
      "days_since_latest_release": 62,
      "mean_days_between_releases": 33.9
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 75,
      "has_issue_template": false,
      "has_code_of_conduct": true,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": [
        {
          "name": "ttsim-backend",
          "exists": true,
          "license": null,
          "keywords": [
            "Benefits",
            "Economics",
            "Pensions",
            "Taxes",
            "Transfers",
            "Intended Audience :: Science/Research",
            "License :: OSI Approved :: GNU Affero General Public License v3",
            "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
            "Operating System :: MacOS :: MacOS X",
            "Operating System :: Microsoft :: Windows",
            "Operating System :: POSIX",
            "Operating System :: Unix",
            "Programming Language :: Python :: 3 :: Only",
            "Programming Language :: Python :: 3.11",
            "Programming Language :: Python :: 3.12",
            "Programming Language :: Python :: 3.13",
            "Programming Language :: Python :: 3.14"
          ],
          "ecosystem": "pypi",
          "matches_repo": true,
          "registry_url": "https://pypi.org/project/ttsim-backend/",
          "is_deprecated": false,
          "latest_version": "1.2.1",
          "repository_url": "https://github.com/ttsim-dev/ttsim",
          "versions_count": 10,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": "2025-07-24T13:53:24.377332Z",
          "latest_published_at": "2026-05-25T11:01:50.813290Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 62
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 2,
      "watchers": 2,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 12
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [
        "notebooks"
      ],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 61629,
      "source_files_sampled": 115,
      "oversized_source_files": 1,
      "agent_instruction_files": [
        "AGENTS.md",
        "CLAUDE.md",
        "GEMINI.md"
      ],
      "agent_instruction_max_bytes": 6112
    },
    "dependencies": {
      "manifests": [
        "pyproject.toml",
        "src_mettsim/pyproject.toml"
      ],
      "advisories": {
        "error": null,
        "scope": "published_package",
        "source": "osv",
        "findings": [],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 49,
        "malicious_count": 0,
        "assessed_package": "pypi:ttsim-backend@1.2.1",
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "pypi"
      ],
      "dependencies": [
        {
          "name": "beartype",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.18"
        },
        {
          "name": "dags",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.6"
        },
        {
          "name": "ipywidgets",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "jaxtyping",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.3.10"
        },
        {
          "name": "kaleido",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.1"
        },
        {
          "name": "networkx",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3.5"
        },
        {
          "name": "numpy",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "numpy-groupies",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "openpyxl",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "optree",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.16"
        },
        {
          "name": "pandas",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3"
        },
        {
          "name": "plotly",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=6.5"
        },
        {
          "name": "portion",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "pygments",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "pygraphviz",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "pytest",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        },
        {
          "name": "pyyaml",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": null
        }
      ],
      "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": 4,
        "merged_prs": 81,
        "open_issues": 8,
        "closed_ratio": 0.778,
        "closed_issues": 28,
        "closed_unmerged_prs": 25
      },
      "bus_factor": 3,
      "bot_contributors": 2,
      "top_contributors": [
        {
          "type": "User",
          "login": "hmgaudecker",
          "commits": 155,
          "avatar_url": "https://avatars.githubusercontent.com/u/158456?v=4"
        },
        {
          "type": "User",
          "login": "MaxBlesch",
          "commits": 106,
          "avatar_url": "https://avatars.githubusercontent.com/u/33116902?v=4"
        },
        {
          "type": "User",
          "login": "MImmesberger",
          "commits": 97,
          "avatar_url": "https://avatars.githubusercontent.com/u/74215010?v=4"
        },
        {
          "type": "User",
          "login": "Eric-Sommer",
          "commits": 67,
          "avatar_url": "https://avatars.githubusercontent.com/u/44068467?v=4"
        },
        {
          "type": "User",
          "login": "tobiasraabe",
          "commits": 42,
          "avatar_url": "https://avatars.githubusercontent.com/u/22533006?v=4"
        },
        {
          "type": "User",
          "login": "LauraGergeleit",
          "commits": 23,
          "avatar_url": "https://avatars.githubusercontent.com/u/93579663?v=4"
        },
        {
          "type": "User",
          "login": "janosg",
          "commits": 22,
          "avatar_url": "https://avatars.githubusercontent.com/u/9536380?v=4"
        },
        {
          "type": "User",
          "login": "mjbloemer",
          "commits": 21,
          "avatar_url": "https://avatars.githubusercontent.com/u/31305679?v=4"
        },
        {
          "type": "User",
          "login": "lars-reimann",
          "commits": 20,
          "avatar_url": "https://avatars.githubusercontent.com/u/2501322?v=4"
        },
        {
          "type": "User",
          "login": "JuergenWiemers",
          "commits": 9,
          "avatar_url": "https://avatars.githubusercontent.com/u/22220065?v=4"
        }
      ],
      "contributors_sampled": 28,
      "top_contributor_share": 0.255
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "main.yml",
        "publish-to-pypi.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": true,
      "has_precommit_config": true
    },
    "security_signals": {
      "lockfiles": [],
      "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": null,
            "reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
            "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": 9,
            "reason": "Found 27/30 approved changesets -- score normalized to 9",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 16 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "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": 10,
            "reason": "18 commit(s) and 10 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "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": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "0fdc84b1753d52b3a35015a966dcb250d98c39aa",
        "ran_at": "2026-07-26T19:58:00Z",
        "aggregate_score": 6.6,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-01T00:43:30Z",
      "oldest_open_prs": [
        {
          "number": 138,
          "created_at": "2026-06-27T12:24:58Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 141,
          "created_at": "2026-06-27T12:25:05Z",
          "last_comment_at": "2026-06-27T12:28:49Z",
          "last_comment_author": "codecov"
        },
        {
          "number": 142,
          "created_at": "2026-07-01T00:43:28Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 143,
          "created_at": "2026-07-06T17:05:25Z",
          "last_comment_at": "2026-07-06T17:07:52Z",
          "last_comment_author": "codecov"
        }
      ],
      "last_merged_pr_at": "2026-07-17T12:50:38Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 29,
          "created_at": "2025-07-23T09:47:16Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 117,
          "created_at": "2026-06-03T15:52:34Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 118,
          "created_at": "2026-06-03T15:52:35Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 119,
          "created_at": "2026-06-03T15:52:37Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 120,
          "created_at": "2026-06-03T15:52:39Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 121,
          "created_at": "2026-06-03T15:52:40Z",
          "last_comment_at": "2026-06-03T20:22:45Z",
          "last_comment_author": "MImmesberger"
        },
        {
          "number": 128,
          "created_at": "2026-06-06T12:26:21Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 134,
          "created_at": "2026-06-16T19:52:25Z",
          "last_comment_at": "2026-06-16T20:33:19Z",
          "last_comment_author": "MImmesberger"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/ttsim-dev/ttsim",
    "host": "github.com",
    "name": "ttsim",
    "owner": "ttsim-dev"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 70,
      "inputs": {
        "security": 73,
        "vitality": 86,
        "community": 34,
        "governance": 74,
        "engineering": 78
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 86,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 77,
            "inputs": {
              "commits_last_year": 62,
              "human_commit_share": 0.97,
              "days_since_last_push": 0,
              "active_weeks_last_year": 22
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "22/52 weeks with commits",
                "points": 15.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 22
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "62 commits in the last year",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 62
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "18 commit(s) and 10 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "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": 100,
            "inputs": {
              "releases_count": 10,
              "latest_release_tag": "v1.2.1",
              "releases_from_tags": false,
              "days_since_latest_release": 62,
              "mean_days_between_releases": 33.9
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "10 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 10
                    }
                  }
                ],
                "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 ~33.9 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 33.9
                    }
                  }
                ],
                "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": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 32,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 32 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 32
                    }
                  }
                ],
                "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": 34,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 1,
            "inputs": {
              "forks": 0,
              "stars": 2,
              "watchers": 2,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "2 stars",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "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": "2 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": true,
              "has_pull_request_template": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (AGPL-3.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "AGPL-3.0"
                    }
                  }
                ],
                "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": 13.5,
                "status": "met",
                "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": 6.3,
                "status": "met",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "good",
        "name": "Sustainability & Governance",
        "value": 74,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "good",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 76,
            "inputs": {
              "bus_factor": 3,
              "contributors_sampled": 28,
              "top_contributor_share": 0.255
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "3 contributor(s) cover half of all commits",
                "points": 36,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 26% of commits",
                "points": 16.8,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 26
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "28 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 28
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 16 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 79,
            "inputs": {
              "merged_prs": 81,
              "open_issues": 8,
              "closed_issues": 28,
              "issue_closed_ratio": 0.778,
              "closed_unmerged_prs": 25
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "78% of issues closed",
                "points": 36.4,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 78
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "81/106 decided PRs merged",
                "points": 29.2,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 81,
                      "decided": 106
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 27/30 approved changesets -- score normalized to 9",
                "points": 13.5,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 46,
            "inputs": {
              "followers": 6,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "ttsim-dev",
              "public_repos": 7,
              "account_age_days": 516
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "6 followers of ttsim-dev",
                "points": 6.1,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 6,
                      "login": "ttsim-dev"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "7 public repos, account ~1 yr old",
                "points": 9.4,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 7
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 1
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "ttsim-backend"
              ],
              "ecosystems": "pypi",
              "any_deprecated": false,
              "min_days_since_publish": 62
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 62 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 62
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "10 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 10
                    }
                  }
                ],
                "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": "good",
        "name": "Engineering Quality",
        "value": 78,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 94,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": true
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "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": 16,
                "status": "met",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 9.6,
                "status": "met",
                "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": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": "https://gettsim.readthedocs.io/",
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://gettsim.readthedocs.io/",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "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": "good",
        "name": "Security",
        "value": 73,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Branch-Protection, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "branch_protection",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 66,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 6.6
            },
            "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": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "28 out of 28 merged PRs checked by a CI test -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "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 27/30 approved changesets -- score normalized to 9",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 16 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "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": "18 commit(s) and 10 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "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": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "excellent",
            "name": "Dependency advisories",
            "note": "Excluded from scoring (no data or not applicable): No advisories left outstanding. Remaining weights renormalized. Matched the pypi:ttsim-backend@1.2.1 runtime dependency closure — what installing the published package pulls in — 49 packages. Reachability is not analyzed.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "no_advisories_left_outstanding"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              },
              {
                "code": "advisories_scope_published",
                "params": {
                  "package": "pypi:ttsim-backend@1.2.1",
                  "assessed": 49
                }
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 0,
              "affected_packages": 0,
              "assessed_packages": 49,
              "unassessed_packages": 0,
              "affected_by_severity": "none",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "no indirect dependency carries a known advisory",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "no_indirect_advisories",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory carries a publication date",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_no_publication_date",
                    "params": {}
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "excellent",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 49,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "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": 12
            },
            "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": "moderate",
        "name": "AI Readiness",
        "value": 60,
        "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.763,
              "agent_instruction_files": [
                "AGENTS.md",
                "CLAUDE.md",
                "GEMINI.md"
              ],
              "agent_instruction_max_bytes": 6112
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "AGENTS.md, CLAUDE.md, GEMINI.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "AGENTS.md, CLAUDE.md, GEMINI.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": "74 of 97 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 74,
                      "sampled": 97
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 51,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0.23,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0.02
            },
            "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": 11,
                "status": "met",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "23 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 23,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "2 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 2,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 54,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 61629,
              "source_files_sampled": 115,
              "oversized_source_files": 1
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "1/115 source files over 60KB",
                "points": 54.5,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 115,
                      "oversized": 1
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          },
          {
            "key": "ai_interfaces",
            "band": "at_risk",
            "name": "Machine-readable interfaces",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "example_dirs": [
                "notebooks"
              ],
              "has_mcp_signal": false,
              "api_schema_files": []
            },
            "components": [
              {
                "key": "api_schema_openapi_graphql_proto",
                "name": "API schema (OpenAPI/GraphQL/proto)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 40
              },
              {
                "key": "mcp_server",
                "name": "MCP server",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "runnable_examples",
                "name": "Runnable examples",
                "detail": "notebooks",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "notebooks"
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          }
        ],
        "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": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "Could not fetch pypi package 'mettsim' from its registry",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-26T19:58:27.877413Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/t/ttsim-dev/ttsim.svg",
  "full_name": "ttsim-dev/ttsim",
  "license_state": "standard",
  "license_spdx": "AGPL-3.0"
}

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 agregadasPyPI.