Registro público
Informe de salud del softwareesquema 0.27.0 · métricas 1.13.0 · 2026-07-28 09:47 UTC

dereuromark / cakephp-queue-scheduler

CakePHP Addon for Queue plugin to schedule commands and queue tasks as crontab like DB solution

PHPMIT★ 7 estrellas⑂ 0 forksdesde oct 2023Ver en GitHub ↗

dereuromark/cakephp-queue-scheduler tiene un índice de salud de 65 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (86/100) y la más baja, Community & Adoption (42/100). Se actualizó por última vez hace 30 días. Una sola persona concentra la mayor parte del trabajo reciente.

65
global / 100
Moderado

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

65
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

Mark SchererCuenta personal
750 seguidores123 repositorios públicosdesde dic 2008Available as (Cake)PHP expert

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

Ecosistemas de paquetes

RegistroPaqueteVersiónDescargas / mesVersionesÚltima publicaciónEtiquetas
Packagistdereuromark/cakephp-queue-scheduler0.3.6461426hace 60 díasqueueplugincroncakephpautomationadmin-panelrecurringschedulerstandalone-ui

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
28.8/36Recencia de push — último push hace 30 días
20.1/36Cadencia de commits — 29/52 semanas con commits
18/18Volumen de commits — 110 commits en el último año
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year110
human_commit_share1
days_since_last_push30
active_weeks_last_year29
Cómo se puntúa
27/27Publica versiones — 26 versiones publicadas
36/36Recencia de las versiones — última versión hace 60 días
27/27Cadencia de publicación — una versión cada ~13,7 días
0/10OpenSSF Scorecard: Signed-Releases — sin datos
Datos de entrada utilizados
releases_count26
latest_release_tag0.3.6
releases_from_tagsno
days_since_latest_release60
mean_days_between_releases13,7
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?

42En riesgo · 18% del índice global
Cómo se puntúa
12.6/60Estrellas — 7 estrellas
0/25Forks — 0 forks
0/15Observadores — 1 observadores
Datos de entrada utilizados
forks0
stars7
watchers1
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (MIT)
18/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
has_contributing
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno
Cómo se puntúa
48.9/80Descargas mensuales — 4614 descargas/mes en packagist
2/20Dependientes en el registro — 1 paquetes dependen de él
Datos de entrada utilizados
packagesdereuromark/cakephp-queue-scheduler
dependents1
ecosystemspackagist
total_downloads22.287
monthly_downloads4614

Sostenibilidad y Gobernanza

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

62Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
0/22.5Distribución de commits — el principal contribuyente firma el 100% de los commits
1.4/13.5Amplitud de contribuyentes — 1 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 3 contributing companies or organizations -- score normalized to 10
Datos de entrada utilizados
bus_factor1
contributors_sampled1
top_contributor_share1
Cómo se puntúa
40.1/46.8Resolución de issues — 86% de issues cerradas
34.6/38.3Aceptación de PR — 38/42 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs38
open_issues1
closed_issues6
issue_closed_ratio0,857
closed_unmerged_prs4
Cómo se puntúa
10/30Respaldo de la propiedad — cuenta personal (usuario)
0/20Dominio verificado — no aplicable a cuentas de usuario
20.7/25Alcance del propietario — 750 seguidores de dereuromark
25/25Trayectoria — 123 repos públicos, cuenta de ~17 años
Datos de entrada utilizados
followers750
owner_typeUser
is_verified
owner_logindereuromark
public_repos123
account_age_days6437
Excluidos de la puntuación (sin datos o no aplicable): Dominio verificado. Los pesos restantes se han renormalizado.
Cómo se puntúa
25/25Publicado y resoluble — 1 paquete(s) en packagist
35/35Recencia de publicación — última publicación hace 60 días
20/20Historial de versiones — 26 versiones en el registro
20/20No obsoleto — activo, ni obsoleto ni retirado
Datos de entrada utilizados
packagesdereuromark/cakephp-queue-scheduler
ecosystemspackagist
any_deprecatedno
min_days_since_publish60

Calidad de Ingeniería

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

84Bueno · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 1 flujo(s) de trabajo
24/24Pruebas presentes
16/16Configuración de linter — phpcs.xml, phpstan.neon
0/9.6Hooks de pre-commit
6.4/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 15 out of 15 merged PRs checked by a CI test -- score normalized to 10
Datos de entrada utilizados
has_ci
has_tests
has_editorconfig
has_linter_config
has_precommit_configno
Cómo se puntúa
30/30README
25/25Directorio de documentación
0/15Sitio de documentación / página del proyecto
10/10Descripción del repositorio
0/10Topics
10/10Wiki
Datos de entrada utilizados
topics
has_wiki
homepage
has_readme
has_docs_dir
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?

44En riesgo · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
0.8/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 15 out of 15 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
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 3 contributing companies or organizations -- score normalized to 10
0/10Dangerous-Workflow — sin datos
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
7.5/7.5Maintained — 30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — sin datos
0/5Pinned-Dependencies — sin datos
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 — sin datos
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated13
scorecard_versionv5.5.0
checks_inconclusive5
scorecard_aggregate4,4
Excluidos de la puntuación (sin datos o no aplicable): dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Los pesos restantes se han renormalizado.

Preparación para IA

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

43En riesgo · 0% del índice global
Cómo se puntúa
0/45Instrucciones para agentes — sin CLAUDE.md / AGENTS.md / reglas de editor
0/15Documentación legible por máquinas (llms.txt)
37.3/40Historial de commits legible — 70 de 100 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share0,7
agent_instruction_files
agent_instruction_max_bytes
Cómo se puntúa
0/18Arranque con un solo comando
22/22Pruebas automatizadas
11/11Configuración de lint / formato — phpcs.xml, phpstan.neon
0/11Verificación estática de tipos
0/10Entorno reproducible
6/10Práctica demostrada con agentes — 3 de los últimos 100 commits con autoría o crédito de agente
0/8Mantenimiento automatizado — no se observan actualizaciones automáticas de dependencias
0/10OpenSSF Scorecard: Pinned-Dependencies — sin datos
Datos de entrada utilizados
has_nixno
has_tests
lockfiles
has_dockerfileno
typed_languageno
bootstrap_files
has_devcontainerno
has_linter_config
typecheck_configs
agent_commit_share0,03
toolchain_manifests
dependency_bot_commit_share0
Excluidos de la puntuación (sin datos o no aplicable): OpenSSF Scorecard: Pinned-Dependencies. Los pesos restantes se han renormalizado.
Cómo se puntúa
0/45Código verificable por tipos — PHP sin configuración de verificación de tipos
55/55Tamaños de archivo manejables — 0/66 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languagePHP
largest_source_bytes34.351
source_files_sampled66
oversized_source_files0

Datos clave

7estrellas de GitHub
1contribuidores
110commits en los últimos 12 meses
30días desde el último push
26versiones publicadas
1factor bus
1issues abiertas
Packagistecosistemas de paquetes

Advertencias de recopilación de datos

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • No resolved dependencies carried a version and a supported ecosystem

Más detalle

OpenSSF Scorecard 4.4 / 10
4.4agregado

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-28 09:47 UTC

10Binary-Artifactsno binaries found in the repo
1Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests15 out of 15 merged PRs checked by a CI test -- score normalized to 10
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
10Contributorsproject has 3 contributing companies or organizations -- score normalized to 10
n/dDangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
n/dPackagingpackaging workflow not detected
n/dPinned-Dependenciesno dependencies found
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/dSigned-Releasesno releases found
n/dToken-PermissionsNo tokens found
10Vulnerabilities0 existing vulnerabilities detected
Dependencias directas 4
RegistroPaqueteRestricción de versiónManifiesto
Packagistcakephp/cakephp^5.1.1composer.json
Packagistdragonmantank/cron-expression^3.3composer.json
Packagistdereuromark/cakephp-tools^3.0.0composer.json
Packagistdereuromark/cakephp-queue^8.9.0composer.json
Todas las dependencias 10

Conjunto completo de dependencias resueltas según el grafo de dependencias de GitHub: 4 paquetes directos y 6 indirectos (transitivos). El cierre transitivo es completo cuando el repositorio incluye un lockfile.

RegistroPaqueteVersiónRelación
Packagistcakephp/cakephpdirecta
Packagistdereuromark/cakephp-queuedirecta
Packagistdereuromark/cakephp-toolsdirecta
Packagistdragonmantank/cron-expressiondirecta
Packagistcakephp/migrationsindirecta
Packagistdereuromark/cakephp-templatingindirecta
Packagistfig-r/psr2r-snifferindirecta
Packagistpanlatent/cron-expression-descriptorindirecta
Packagistphpindirecta
Packagistphpunit/phpunitindirecta
Avisos de dependencias sin evaluar

El cotejo de avisos no pudo ejecutarse para este informe: No resolved dependencies carried a version and a supported ecosystem

Informe JSON sin procesar legible por máquina
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 401,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "PHP": 314350
      },
      "pushed_at": "2026-06-28T09:42:00Z",
      "created_at": "2023-10-18T00:48:03Z",
      "owner_type": "User",
      "updated_at": "2026-06-28T09:42:04Z",
      "description": "CakePHP Addon for Queue plugin to schedule commands and queue tasks as crontab like DB solution",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "master",
      "license_spdx_raw": "MIT",
      "primary_language": "PHP",
      "significant_languages": [
        "PHP"
      ]
    },
    "owner": {
      "blog": "https://www.dereuromark.de/",
      "name": "Mark Scherer",
      "type": "User",
      "login": "dereuromark",
      "company": "Available as (Cake)PHP expert",
      "location": "Berlin",
      "followers": 750,
      "avatar_url": "https://avatars.githubusercontent.com/u/39854?v=4",
      "created_at": "2008-12-11T16:33:44Z",
      "is_verified": null,
      "public_repos": 123,
      "account_age_days": 6437
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "0.3.6",
          "kind": "patch",
          "published_at": "2026-05-28T16:22:31Z"
        },
        {
          "tag": "0.3.5",
          "kind": "patch",
          "published_at": "2026-05-11T23:18:54Z"
        },
        {
          "tag": "0.3.4",
          "kind": "patch",
          "published_at": "2026-05-08T16:51:54Z"
        },
        {
          "tag": "0.3.3",
          "kind": "patch",
          "published_at": "2026-05-04T11:33:03Z"
        },
        {
          "tag": "0.3.2",
          "kind": "patch",
          "published_at": "2026-05-04T00:31:38Z"
        },
        {
          "tag": "0.3.1",
          "kind": "patch",
          "published_at": "2026-05-01T23:13:02Z"
        },
        {
          "tag": "0.3.0",
          "kind": "minor",
          "published_at": "2026-04-30T22:07:26Z"
        },
        {
          "tag": "0.2.15",
          "kind": "patch",
          "published_at": "2026-04-02T14:58:34Z"
        },
        {
          "tag": "0.2.14",
          "kind": "patch",
          "published_at": "2026-01-30T09:19:30Z"
        },
        {
          "tag": "0.2.13",
          "kind": "patch",
          "published_at": "2026-01-25T05:36:04Z"
        },
        {
          "tag": "0.2.12",
          "kind": "patch",
          "published_at": "2026-01-04T04:44:08Z"
        },
        {
          "tag": "0.2.11",
          "kind": "patch",
          "published_at": "2025-11-09T08:56:01Z"
        },
        {
          "tag": "0.2.10",
          "kind": "patch",
          "published_at": "2025-09-16T12:45:13Z"
        },
        {
          "tag": "0.2.9",
          "kind": "patch",
          "published_at": "2025-04-30T00:46:28Z"
        },
        {
          "tag": "0.2.8",
          "kind": "patch",
          "published_at": "2025-03-10T01:28:11Z"
        },
        {
          "tag": "0.2.7",
          "kind": "patch",
          "published_at": "2024-11-18T14:22:29Z"
        },
        {
          "tag": "0.2.6",
          "kind": "patch",
          "published_at": "2024-10-26T12:11:12Z"
        },
        {
          "tag": "0.2.5",
          "kind": "patch",
          "published_at": "2024-07-18T13:24:24Z"
        },
        {
          "tag": "0.2.4",
          "kind": "patch",
          "published_at": "2024-03-29T23:38:52Z"
        },
        {
          "tag": "0.2.3",
          "kind": "patch",
          "published_at": "2024-03-12T16:38:56Z"
        },
        {
          "tag": "0.2.2",
          "kind": "patch",
          "published_at": "2024-03-06T23:37:42Z"
        },
        {
          "tag": "0.2.1",
          "kind": "patch",
          "published_at": "2023-12-11T22:24:41Z"
        },
        {
          "tag": "0.1.2",
          "kind": "patch",
          "published_at": "2023-12-11T22:24:22Z"
        },
        {
          "tag": "0.2.0",
          "kind": "minor",
          "published_at": "2023-11-16T00:58:19Z"
        },
        {
          "tag": "0.1.1",
          "kind": "patch",
          "published_at": "2023-11-16T00:54:40Z"
        },
        {
          "tag": "0.1.0",
          "kind": "minor",
          "published_at": "2023-10-26T12:14:05Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "6caadcf36793f03190eefc112c9391f9cb4e463d",
          "body": "actions/cache@v1-v4 declare Node 20, which GitHub now deprecates and\nforce-runs on Node 24. v5 is Node 24 native and removes the warning.",
          "is_bot": false,
          "headline": "CI: bump actions/cache to v5 (Node 24)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-06-28T09:41:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "77922d55a81afa7b29a3fec0d397b72842dd8721",
          "body": "Newer phpstan (2.2.x, as installed by CI) flagged two provably-constant\ncomparisons in SchedulerRow:\n- isWithinWindow(): `$endMinutes !== null` was always true at that point\n  (both-null returns early, start-only handled above), so drop it.\n- windowIntervalsByDay(): the seconds null-guard was unreac\n[…]\nplace the exact `assertSame(300, ageSeconds)` in the stale-heartbeat\ntest with a range assertion; a second can elapse between writing\n`time() - 300` and the controller reading it, which flaked to 301.",
          "is_bot": false,
          "headline": "Fix CI: phpstan dead comparisons and flaky heartbeat age assertion",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-06-28T09:25:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "41794e01691427b89758f88a00394ac6779adbe5",
          "body": "… (#48)\n\n* Rerun terminally-failed scheduled jobs in place, with failure backoff\n\nA non-concurrent row gates its next dispatch on QueuedJobsTable::isQueued().\nOnce cakephp-queue records terminal \"aborted\" state, a dead job stops\ncounting as queued, so the schedule resumes — but it would then queue a\n[…]\nthe transaction commits, so a listener never runs mid-transaction.\n- Tidy a detached test docblock left over from the earlier insertion.\n\n* Reference cakephp-queue#505 in the reset-status shim comment",
          "is_bot": false,
          "headline": "Rerun terminally-failed scheduled jobs in place, with failure backoff…",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-28T16:13:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b79cfe41cfbf79b2c16b56b5763e316cc74acfcf",
          "body": "* AP-0000 Add QueueScheduler import/export workflow\n\n* Fix scheduler window day form submission\n\n* Fix scheduler admin template structure",
          "is_bot": false,
          "headline": "Add QueueScheduler import/export workflow (#46)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-26T21:13:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d87281c110ec6e542a4c159444fc6e845ed50215",
          "body": null,
          "is_bot": false,
          "headline": "Add sort direction indicators to admin tables",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-26T20:54:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "24b7f8196a8b2c461523aa801fe916bf321ea158",
          "body": "* Apply conservative Rector cleanup\n\n* Run PHPCS cleanup\n\n* Restore compact() for matching view vars\n\n* Simplify null guard for scheduler helper\n\n* Restore compact() for matching view vars\n\n* Restore explicit null check for cron detection",
          "is_bot": false,
          "headline": "Apply conservative Rector cleanup (#45)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-25T12:19:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "79f233f575150771a2c74042658930868c07ff3d",
          "body": "Point readers to https://toolbox.dereuromark.de/dbml so they can convert this\nDBML snapshot into the migration or raw SQL they need for their own app.",
          "is_bot": false,
          "headline": "Link the DBML converter in the schema snapshot",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-23T15:54:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7dcfd971784a43c54de68e4948f46935b2fff6a1",
          "body": "Hand-maintained DBML snapshot of the plugin's migration schema under\nresources/schema/schema.dbml — paste into dbdiagram.io to view/diagram.\nMirrors the snapshot already shipped by cakephp-workflow.",
          "is_bot": false,
          "headline": "Add DBML database schema snapshot",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-23T12:54:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "394b10bc622d0dcc9aae47a0c4e264b4dc9597b4",
          "body": null,
          "is_bot": false,
          "headline": "Add .github/CONTRIBUTING.md",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-22T18:51:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f06395f731ab8bb74df3217f3dc5577f00098e70",
          "body": "Several tests temporarily froze DateTime::setTestNow() to a past date and\n\"reset\" it afterwards with setTestNow(new DateTime()). While an override is\nactive, new DateTime() resolves to the frozen value, so the reset re-froze\nthe same past date and leaked it into later tests.\n\nRowTest::testCalculateN\n[…]\n clears the override before re-freezing at the\nreal wall clock. This avoids leaking a stale value while keeping test-now\nnon-null for tests that read getTestNow() (SchedulerRowsTableTest::testInsert).",
          "is_bot": false,
          "headline": "Fix test-now leak that made RowTest fail in CI (#44)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-21T13:52:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e94278e4418855a9d24f0e5bb3c4f082ec924f97",
          "body": null,
          "is_bot": false,
          "headline": "Document missing configuration keys in config/app.example.php",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-21T13:11:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "98a5d3341eee5f12e21a07d5cd33ac6626e60b7b",
          "body": null,
          "is_bot": false,
          "headline": "Add homepage to composer.json",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-21T12:06:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a4da3126d675b52bbb8c1a1484d6a6b9c47b9d0a",
          "body": "The page-header pattern (title + action buttons in\n`d-flex justify-content-between align-items-center`) pushed buttons\noff-viewport on phones because no wrap was allowed. Wrap on viewports\n< sm so buttons fall to a new row instead of being clipped.",
          "is_bot": false,
          "headline": "Make page-header row wrap on phones so action buttons stay on-screen",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T23:37:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b0f036d02abe94b897dfc63adab1eacee81d873e",
          "body": "The mobile offcanvas nav was missing the Reference -> Commands & Tasks\nlink that the desktop sidebar exposes. Mobile users had no way to reach\nthe available-commands listing without typing the URL manually.",
          "is_bot": false,
          "headline": "Sync mobile_nav with sidebar: add missing Commands & Tasks link",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T23:35:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a20a4e61eb65ba049d58404f1345d1ea5c774326",
          "body": "CronExpression::getNextRunDate() with the default arg resolves \"now\" via\nDateTimeImmutable('now'), which ignores Cake's Chronos::setTestNow. The\nprefer-lowest CI matrix happened to run during a real-time minute that\nsat inside the test's 23:00-23:30 window, so both the pre-patch cron\nresult and the \n[…]\ndary.\n\nUpdate testCalculateNextRunForMinutelyShortcut to compare against the\ntest-now clock rather than time(). Its previous reliance on real time()\nwas a workaround for the very bug being fixed here.",
          "is_bot": false,
          "headline": "Fix master: make calculateNextRun honor DateTime::setTestNow (#42)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T23:18:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1bc35f3b50693b8f60615192bb48d4ce90c5e50d",
          "body": "* Complete scheduler time-window UX and localization\n\n* Fix CI for time-window follow-up",
          "is_bot": false,
          "headline": "Complete time-window scheduler UX and localization (#41)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T22:58:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0994f9704057b17c24661676065465475dc58228",
          "body": "* Add time-window restrictions to SchedulerRow dispatch gating\n\nSecond of three queue-scheduler strategic items from the audit. Cron\nexpressions handle \"every Monday at 9\" but cannot express \"every 5 min,\nbut only between 09:00-18:00 on weekdays\" — those need compound\nrestrictions ANDed against the \n[…]\ny Options covering the three new columns (window_start_time,\nwindow_end_time, window_days_of_week), the overnight-wrap semantics,\nand three worked examples (business hours / overnight / weekend-only).",
          "is_bot": false,
          "headline": "Add time-window restrictions to SchedulerRow dispatch gating (#39)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T22:00:23Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7634e95f0773ee280091ffac9e8b5b92e87d2081",
          "body": "* Add ad-hoc trigger-now with per-call param and job_config overrides\n\nAdds a second \"Run Now\" path for Queue task rows in the admin UI that\nlets operators dispatch a single override job without touching the\nrow's scheduled cadence. Use case: incident-response re-runs (rerun\nyesterday's batch with a\n[…]\n enough to look like real field values, which is misleading in the\noverride JSON textareas (and elsewhere in the admin UI). Override to the\ngray-500 token so empty fields read clearly as placeholders.",
          "is_bot": false,
          "headline": "Ad-hoc trigger-now with per-call param/job_config overrides (#40)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T22:00:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2ae29cc9a0adc06f8e97a9cc3f23f3cc8d3ebe11",
          "body": "* Fix isDue stale-next_run loop and racy run() compare-and-swap\n\nTwo correctness bugs from the source-grounded review:\n\n1. SchedulerRow::isDue() short-circuited on next_run and ignored last_run.\n   If a dispatcher crashed between createJob() and the next_run-advancing\n   save, the row stayed in an \"\n[…]\nced the plugin registry, leaving subsequent CommandFinderTest::testAll\nunable to find Tools.Inflect. Reload all three so the registry matches what\nApplication::bootstrap() establishes in the test app.",
          "is_bot": false,
          "headline": "Fix isDue stale-next_run loop and racy run() compare-and-swap (#37)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-11T14:26:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "33574240fbb77290992f1fec15ea11311d046cf2",
          "body": null,
          "is_bot": false,
          "headline": "Fix CS.",
          "author_name": "Mark",
          "author_login": "dereuromark",
          "committed_at": "2026-05-09T18:47:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ecb435bc8467496ab4a28c859bc134b8fcf80651",
          "body": "Two ergonomics fixes for the Param field on Queue Task and Cake Command rows:\n\nAuto-normalize empty-collection literals. The validators reject `[]` and\n`{}` via `!empty($decoded)`, but the field already accepts an empty string\nto mean \"no payload / no args\". A user who explicitly types the empty\nlit\n[…]\narded straight to `Command::run($args, $io)`, so embedded\nshell-style quoting (`\"--some-option \\\"Some value\\\"\"`) does not behave as\nit would on a real shell — replaced with `--some-option=Some value`.",
          "is_bot": false,
          "headline": "Normalize empty-collection JSON params to blank; polish param docs (#36)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-08T16:26:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a0574f5fcb66936168cf3b967aed82c1f6c78441",
          "body": "… (#35)\n\n* Tokenize shell-command rows into executable and arguments on dispatch\n\nPreviously the entire scheduler `content` field was assigned to\n`Queue.Execute`'s `command` verbatim. The queue plugin matches `command`\nagainst `Queue.executeAllowedCommands` literally and `escapeshellarg`'s\neach `par\n[…]\nlready\nrejects empty content at save time, but a row inserted via raw SQL or a\nmarshalling path that bypasses validation can no longer produce a params\nlist that includes a literal empty-string entry.",
          "is_bot": false,
          "headline": "Tokenize shell-command rows into executable and arguments on dispatch…",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-08T16:13:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6b05cca12e6c414ea46464a3a6d432f9c945a1e5",
          "body": "Reads QueueScheduler.adminBackUrl + optional QueueScheduler.adminBackLabel\n(defaults to \"Back to App\"). Mirrors the same pattern in the other\ndereuromark plugins so apps can wire all of them with one consistent\nconfig shape.",
          "is_bot": false,
          "headline": "Add configurable Back-to-App link to admin header",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-04T12:30:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "26568bc33e97957749b5ec38045333307773149d",
          "body": "SchedulerRowsTable::initialize() called setColumnType('job_config', 'json')\nunconditionally, which throws DatabaseException if the column doesn't exist\nyet. On an upgrade from 0.2.x where the table is loaded via TableRegistry\nbefore migrations migrate has run, this leaves the deploy unrecoverable.\n\nGuard the cast on hasColumn() so booting against a not-yet-migrated schema\nno longer crashes; the cast attaches once the column lands.",
          "is_bot": false,
          "headline": "Guard job_config column-type cast against pre-migration schema (#34)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-04T11:32:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "909f78d62e4e46e5b6266e3185cf07754c70bea7",
          "body": "Convert __() / __n() calls in src/ and templates/ to __d('queue_scheduler', ...) /\n__dn('queue_scheduler', ...) so user-facing strings live in their own translation\ndomain instead of leaking into the host app's default domain.\n\nAdd resources/locales/queue_scheduler.pot generated via cake i18n extract so\ntranslators have a stable POT to base language files on.",
          "is_bot": false,
          "headline": "Use plugin-specific i18n domain for translations (#32)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-04T00:30:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "14a40565d641fb2a4a7466375b4f9ec8f0ef03de",
          "body": "Switched the Paginator nav titles from escapeTitle => false to\nescape => false. PaginatorHelper only honors the escape option —\nescapeTitle is silently ignored — so the FontAwesome <i> tags fell back\nto the default escaped path and rendered as literal HTML text.\n\nVerified in cakephp/cakephp PaginatorHelper: prev/next/first/last/sort\nall use only the escape option, with no narrower title-only equivalent.",
          "is_bot": false,
          "headline": "Fix pagination icons rendering as raw text (#31)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-03T15:59:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3032342b8744f4ed9d728939f19307fc1cab9b83",
          "body": "Tightens row-save validation along three axes that were previously single-\ngated or implicitly trusted:\n\n- `validateShellCommand` now requires `QueueScheduler.allowRaw=true` (or\n  `debug=true`) at row-authoring time, mirroring the dispatch-side gate in\n  `findActive()`. Rows of `TYPE_SHELL_COMMAND` \n[…]\nnow dispatches with empty params instead of crashing.\n\nAlso widens `validateContent` to `string|bool` so the new `validateShell-\nCommand` can return a translated error message instead of just `false`.",
          "is_bot": false,
          "headline": "Gate shell authoring on allowRaw and validate class types (#30)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-02T14:32:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d35a4618ea85c5b27507ffcab2eee8ce4012eee0",
          "body": "When next_run sits more than 5x the schedule interval in the past (e.g.\nan every-minute job with next_run 9 hours ago because cron was down or\nthe worker was stuck), the relative time was technically correct but\nuninformative — \"(9 hours, 35 minutes ago)\" tells the user nothing they\ncan act on. The \n[…]\nals on the next successful tick: calculateNextRun re-derives\nnext_run from CronExpression::getNextRunDate() (or last_run + interval),\nboth of which produce a future timestamp once last_run is updated.",
          "is_bot": false,
          "headline": "Show \"overdue\" instead of long ago time when next run is grossly overdue",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-01T23:01:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f801c708578b5baf277153f73c1a37170490ebf1",
          "body": "Adds a \"Run New\" button to /admin/queue-scheduler that queues all enabled\nschedules with last_run IS NULL. The button only renders when at least 2\nsuch rows exist; for a single new row, the per-row Run action is enough.\n\nUseful after bulk-adding long-interval schedules (weekly/monthly) where\nwaiting for the first cron tick is impractical.",
          "is_bot": false,
          "headline": "Add Run New action to scheduler dashboard",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-01T13:55:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "edd6a0f04295c0a01443cc12f9ca57063d71d3c3",
          "body": "Same shape of improvements that landed on the index, plus a small DRY\nrefactor: the duration formatting, ratio-based color class, and\nlast-run pass/fail icon now live as methods on SchedulerHelper so both\ntemplates render them the same way without duplicating logic inline.\n\nSchedulerHelper additions\n[…]\n threshold also go through the helper.\n\nSchedulerRowsController::view() now contains LastQueuedJob (id,\nfetched, completed, failure_message) so the new view-page bits resolve\nwithout a per-row lookup.",
          "is_bot": false,
          "headline": "Bring scheduler view page in line with the index polish",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-01T03:43:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e1f91a1c7fef7b6fa0407d55fe80bfe6d3916c81",
          "body": "- Rename the \"Log\" column header to \"Status\".\n- Surface success / failure on the last run with a check / x icon next\n  to the timestamp, driven by the linked QueuedJob's failure_message.\n- Render an explicit empty-state row when there are no schedules.\n- Lift colored spans (warning / danger duration\n[…]\ntton form submission,\nshows confirm, posts via fetch with the spinner shown in-place, and\nreloads the page once the queue layer reports success. Non-JS clients\nkeep the original flash + redirect flow.",
          "is_bot": false,
          "headline": "Polish scheduler index UI",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-01T03:22:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a6dee013c56498e9223afb567dddf8a1c282ec9b",
          "body": "Last Run row now appends the actual execution duration of the latest\nqueued job (e.g. \"(2.3s)\", \"(1m 30s)\"), pulled in via a new LastQueuedJob\nbelongsTo association on SchedulerRows. The duration is color-coded\nrelative to the schedule interval: text-warning at >= 80% of the\ninterval, text-danger at\n[…]\nw::calculateIntervalSeconds() which returns the typical\ngap between firings for both interval-style (\"+5 minutes\", \"PT5M\") and\ncron-expression frequencies, used as the yardstick for the warning bands.",
          "is_bot": false,
          "headline": "Show run duration and time-to-next-run on the scheduler index",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-05-01T03:07:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a9d7e610ed66cd60f3c24af7e5912ef11afb4993",
          "body": "Make it explicit that exactly one scheduler runner should fire against\na given database. The FileLock only guards same-host overlap, so\nmulti-host fleets either pin cron to one host (common case) or swap\nin a cross-host lock (advisory lock / Redis).\n\nReplaces the buried multi-host caveat in the sub-minute section with\na back-reference, so the rule is stated once and prominently.",
          "is_bot": false,
          "headline": "Document single-runner recommendation for scheduler",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T23:49:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d99e8c6d56e3cddc328f05fc8a031e449c9877fa",
          "body": "* Surface scheduler heartbeat on admin index\n\nRunCommand writes a unix timestamp to the cache key QueueScheduler.lastTick\nat the end of every successful (non-dry-run) pass. The admin index page\nreads it and shows a small status pill: healthy, stale, or never run.\n\nCache config defaults to 'default' \n[…]\nlthy and stale.\n\n* Untrack accidentally-committed .claude/ scratch file\n\nRemoves .claude/scheduled_tasks.lock that slipped into the previous\ncommit and adds /.claude/ to .gitignore so it cannot recur.",
          "is_bot": false,
          "headline": "Surface scheduler heartbeat on admin index (#29)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T23:11:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2c9b15ad79860ee5aa00a7bd95437a1a31f145b8",
          "body": "Using 'escape' => false also disables HTML escaping of attributes (URL, classes, title), not just the title text. The narrower 'escapeTitle' => false keeps attribute escaping on while still allowing the icon HTML in the title.",
          "is_bot": false,
          "headline": "Use escapeTitle instead of escape in pagination element (#28)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T23:09:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3cc02b8af7b093a09bfd3ff60a5762ac02e2440b",
          "body": "Cleaner than the inline FQCN now that the file already imports other\nCake classes.",
          "is_bot": false,
          "headline": "Use ServerRequest import in app.example.php",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T15:44:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f2f8e925f90dc5946d9365015a9a20a401381c49",
          "body": "These are working documents only (specs, plans, brainstorm output) and\nmust not be in the repo. The 2026-04-30-command-output-capture.md spec\nslipped in as a side-effect of an unrelated commit; untrack it and add\ndocs/superpowers/ to .gitignore so it cannot recur.\n\nThe file stays on the local working tree (just untracked), so anyone\nalready iterating on it keeps their copy.",
          "is_bot": false,
          "headline": "Stop tracking docs/superpowers/ working files",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T15:43:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "195bb487c3f354fa08fd975978e8281a222a599b",
          "body": null,
          "is_bot": false,
          "headline": "Document QueueScheduler.adminAccess in app.example.php",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T14:43:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8d1acfcfd98b5f1954f4dac7c8eeff9c05b9a350",
          "body": "* Set command name in CommandExecuteTask before running\n\nMost app commands override `protected string $name` to a single bare\ntoken (e.g. `'clear_sessions'`), expecting `Cake\\Console\\CommandRunner`\nto rewrite it to `\"cake clear_sessions\"` via `setName()` before running.\n\nCommandExecuteTask invokes t\n[…]\ndy contain a space must not be rewritten by CommandExecuteTask —\nbut the example now mirrors a real-world pattern. Test method renamed\nto testRunDoesNotRewriteMultiWordCommandName for the same reason.",
          "is_bot": false,
          "headline": "Set command name in CommandExecuteTask before running (#27)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T12:52:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "27368e89a05626d72f0e83744a08250a43894dc4",
          "body": "Cover isDue(), calculateNextInterval(), and calculateNextRun() directly on\nthe entity so regressions in the core scheduling logic surface here rather\nthan only via the integration tests in SchedulerTest / RunCommandTest.\n\n26 cases across the three methods:\n\n- isDue(): next_run past/future/equal-now \n[…]\nCake's setTestNow.\ntearDown restores a fresh test-now (instead of clearing to null) so the\nexisting SchedulerRowsTableTest::testInsert keeps finding a non-null\nChronos::getTestNow() across test files.",
          "is_bot": false,
          "headline": "Add direct unit tests for SchedulerRow scheduling math",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T11:57:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c1ea4bbadadce57732cde43cfcb2be4934701bdf",
          "body": "…rontabMinimum (#26)\n\n- Bump composer.json branch-alias from 0.2.x-dev to 0.3.x-dev so Packagist\n  picks up dev-master under the right next-release banner.\n- Document QueueScheduler.adminLayout (null / false / string layout name)\n  in docs/README.md as its own Configuration subsection — previously o\n[…]\nly on but is not read\n  anywhere in src/ or templates/. Documenting a no-op key would mislead\n  users; quietly dropping it is the cleaner path. Restore via PR if it\n  is reserved for a future feature.",
          "is_bot": false,
          "headline": "Bump branch-alias to 0.3.x-dev; document admin UI config; drop dead c…",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T11:29:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c658fd5137d874e7e7d044670a634623bc9a6ff1",
          "body": null,
          "is_bot": false,
          "headline": "Update branch alias for dev-master to 0.3.x-dev",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T11:26:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "28063416e422ef21632b56c990dc4129aa8cd789",
          "body": "… (#25)\n\n* Add --duration and --interval flags for sub-minute scheduling\n\nCron's minimum granularity is one minute, but rows can already declare\nsub-minute frequencies (e.g. `+10 seconds`, `PT5S`). The previous\nRunCommand only fired once per cron tick, so those rows could never run\nat their configur\n[…]\ngumentException when the @-suppressed call\nreturns a non-DateInterval value. Now both versions reach the catch\nthrough the same path, and phpstan on 8.2 stubs sees the throw and\nkeeps the catch alive.",
          "is_bot": false,
          "headline": "Add --duration/--interval flags for sub-minute scheduling (closes #2)…",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T11:10:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f9afa4fc6b708e7b5fed52c6dc8297ff9c9fe338",
          "body": "The migration and fixture stored a comment listing keys (queue, notBefore)\nthat the validator now rejects. Reflect the real allow-list — priority\nand group only — so anyone reading the schema sees the same contract the\nvalidator enforces.\n\nCosmetic-only: no functional schema change beyond the COMMENT text.",
          "is_bot": false,
          "headline": "Tighten job_config column comment to actual allow-list",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T02:08:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a22bb02348bc5b30abe056985b927b8c2407607a",
          "body": "The scheduler admin backend can configure arbitrary scheduled command\nexecution (Cake commands, Queue tasks, and — when allowRaw is on — shell\ncommands), so accidental exposure has real blast radius. Mirror the\ncaptcha plugin's \"fail closed\" pattern: the host app MUST configure\nQueueScheduler.adminA\n[…]\nange: existing 0.2.x installs\nthat just relied on host AppController gating will 403 until they\nadd a Closure. Right tradeoff for a pre-1.0 plugin where the\nexposure cost outweighs the migration cost.",
          "is_bot": false,
          "headline": "Default-deny admin access via QueueScheduler.adminAccess Closure",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T02:07:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "96bda28103e8a20bf3b89ae6efcf6c5631a40685",
          "body": "Form display:\n* Configure FormHelper to emit Bootstrap 5 error markup\n  (errorClass=is-invalid, error template with invalid-feedback) so\n  field-level errors actually render with the red border/text instead\n  of plain unstyled \"form-error\" output.\n* Replace the misleading \"queue\" placeholder/help in\n[…]\nise\n  silently cast to 0 — accidentally the highest priority.\n\nDocs:\n* docs/README.md gains a \"Job Config\" section documenting the allow-list\n  and a \"Command flags\" section for --dry-run and --limit.",
          "is_bot": false,
          "headline": "Improve form error UX and tighten job_config validation",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:48:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2dab38167e1417847e2953de51499bbc9e507910",
          "body": "--dry-run lists the events that would be dispatched and exits without\nenqueueing or touching last_run/next_run. Useful for diagnosing \"why is\nthis not firing yet\" or smoke-testing a freshly added row.\n\n--limit=N caps the number of events dispatched per tick; the remainder\nstays due for the next run. Helps drain a backlog gracefully after\ndowntime instead of flooding the queue all at once.",
          "is_bot": false,
          "headline": "Add --dry-run and --limit flags to scheduler run",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:35:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8c8bd15e509b465d10ff246ab06a2b09110c1c5b",
          "body": "* Remove dead `=== false` / `!== false` guards on\n  DateInterval::createFromDateString — the function cannot return false on\n  PHP 8.2+, and phpstan was correctly flagging both as always-false /\n  always-true. Drops an unreachable RuntimeException and clears the last\n  two phpstan errors so the suit\n[…]\n\n  comments.\n* Drop a misused JSON_PRETTY_PRINT flag from json_decode in two\n  param-shape validators (it's an encode-only flag; integer was just\n  being ignored).\n* Add a branch-alias for dev-master.",
          "is_bot": false,
          "headline": "Clean up small code-quality issues",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:33:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c3597ebfccfa01e14b9c06c883c559522633f465",
          "body": null,
          "is_bot": false,
          "headline": "Queue config.",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:26:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9508a469670d5c633e3c4c7f6097f37203a8073a",
          "body": "The custom @minutely shortcut was being expanded to \"* * * * *\" in five\nplaces (entity, table validator, controller intervals action, view.php\ntwice, intervals.php). Promote SchedulerRow::normalizeCronExpression() to\npublic static and route every caller through it; renaming or extending\nthe shortcut list now happens in one spot.",
          "is_bot": false,
          "headline": "Centralize @minutely cron-shortcut normalization",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:08:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d27b94ef1c7f26cfcc5e5813e27993a13338f019",
          "body": "The admin add/edit screens call all() to populate the command picker; each\ncall walked App::classPath() and DirectoryIterator over the app and every\nloaded plugin. A static per-plugin-set cache keeps the disk walk to once\nper request lifecycle.",
          "is_bot": false,
          "headline": "Cache CommandFinder::all() per loaded plugin set",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:08:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "78f5e6e9a5c531d60a3254c3398dbff9e4a7a4cd",
          "body": "isDue() used strict less-than against next_run while findScheduled()\nfilters with `<=`, so a row whose next_run was exactly \"now\" was selected\nby the SQL query but rejected by the entity check, falling through into\nredundant cron/interval re-evaluation. Use `<=` in both branches so they\nagree.\n\ncalc\n[…]\nly on the next scheduler tick\nrather than at the next 11:00 occurrence. Cron rows now compute their\ntrue next occurrence even on first run; interval rows keep their existing\nfire-immediately behavior.",
          "is_bot": false,
          "headline": "Fix isDue boundary and cron first-run calculation",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:04:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4ed5994f52a9b78e39d77020c91210fd881a728c",
          "body": "Previously a thrown exception inside Scheduler::schedule() would bubble\nout of Collection::each and abort the rest of the batch, while RunCommand\nalways returned exit code 0 — partial failures were invisible to cron\nmonitoring.\n\nNow schedule() catches per-row throwables, logs them, counts them, and\n\n[…]\nfrom real failures.\n\ntests/bootstrap.php gains a FileLog config so the new error-path test\ndoes not blow up writing to a closed console stream after\nConsoleIntegrationTestTrait runs in the same suite.",
          "is_bot": false,
          "headline": "Make scheduler resilient to single-row failures and surface them",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T01:04:47Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e0ddff1d886aaf1cb675b0cc8dc951d9372f1cd7",
          "body": "The Config row used \\$row->config (which does not exist on the entity), so\nthe block never rendered. Switching to \\$row->param actually shows it. Also\nwrap the JSON output in h() — values inside <pre> still need escaping to\nprevent breakout via tags like </pre><script>.\n\nSync SchedulerRowsFixture with the schema (param, last_queued_job_id) so\ntests that exercise these columns can persist them; tests/schema.php\nderives the test DB schema from the fixture's \\$fields.",
          "is_bot": false,
          "headline": "Fix Config block on view page and escape param output",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T00:57:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ea7f63e07020cd683de663e5175a428c9087bf18",
          "body": "Cake's Validator::add() defaults the 'rule' key to the rule's name when\nabsent, so the 'role' => 'X' entries were being silently ignored — a typo\nthat did not actually break validation but kept misleading readers.",
          "is_bot": false,
          "headline": "Drop dead 'role' keys from validator rule arrays",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T00:57:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5f09472f6d6e8ca2a08e4bcd7f7e8603d971cff",
          "body": "Reject anything that isn't a CommandInterface subclass before instantiating\nit. Previously the task did `new $class()` on whatever string the queue\npayload contained, with only a phpdoc claim that the class implemented\nCommandInterface.",
          "is_bot": false,
          "headline": "Validate command class in CommandExecuteTask",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-30T00:57:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b2345f451bf990a54a5d9326639e56ccecca068",
          "body": null,
          "is_bot": false,
          "headline": "Adjust CS badge",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-28T16:58:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b0c94df5661e5b8bb4278c0cd4d503c976d4e96",
          "body": "…titles (#24)\n\n10 admin template links rendering icon HTML in the title were using\n'escape' => false, which also disables escaping of url attributes (href,\nclass, title). Switching to 'escapeTitle' => false scopes the opt-out\nto the title only.\n\nThe 4 'escape' => false entries on Paginator first/prev/next/last are\nleft as-is since PaginatorHelper does not support 'escapeTitle'.",
          "is_bot": false,
          "headline": "Use 'escapeTitle' instead of 'escape' for icon-prefixed Html->link() …",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-27T10:11:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f0d85facee6b3608c853e4878a697fefd4deb352",
          "body": "The button widget honors escapeTitle (not escape) for the title text.\nPassing escape => false on these calls left the icon markup escaped, so\nbuttons rendered with literal &lt;i class=...&gt;...&lt;/i&gt; instead\nof an icon.",
          "is_bot": false,
          "headline": "Use escapeTitle => false for icon HTML in Form->postButton/button",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-27T09:43:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f15c5530299754d2242ffd400e539a32315f4114",
          "body": "* Move mobile-nav background to CSS class (strict-CSP)\n\nDrops the inline `style=\"background: linear-gradient(...)\"` attribute on the\nmobile offcanvas in favour of a `.scheduler-mobile-nav-bg` class that reuses\nthe existing `--scheduler-sidebar-bg` custom property. Removes the\n`style-src 'unsafe-inli\n[…]\nin\n`Admin/SchedulerRows/view.php` with a `.scheduler-col-w-40` class\ndefined in the layout's existing nonced `<style>` block. After this\nthe plugin's templates contain zero inline `style=` attributes.",
          "is_bot": false,
          "headline": "Move mobile-nav background to CSS class (strict-CSP) (#23)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-26T22:30:26Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b50eb68d0f1e98275e2f235d85b083a172935538",
          "body": "- Add nonce attribute to the three inline <script> blocks (layout\n  DOMContentLoaded / tooltip init / auto-refresh, quick-add element,\n  content-autocomplete element) so apps with a strict script-src\n  'self' 'nonce-...' CSP can run them.\n- Replace every Form->postLink with Form->postButton across t\n[…]\nnfirm messages move to a data attribute and use a\ndelegated submit handler instead.\n\nGraceful fallback: when no cspNonce request attribute is set, the\n<script> tags render without the nonce attribute.",
          "is_bot": false,
          "headline": "Make admin UI CSP-compatible (#22)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-22T23:27:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f961e2f3cc197a5734a8042004259f15f46e125b",
          "body": null,
          "is_bot": false,
          "headline": "Fix CS.",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-17T17:30:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "325a52336baf2a43b64eb5f10b6f8113bad86a3f",
          "body": null,
          "is_bot": false,
          "headline": "Fix pre element overflow in standalone layout",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-04-02T14:57:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e151be5d01de38e0286ec38ff63b05121e95998c",
          "body": "Sets explicit Bootstrap 5 templates to avoid app templates affecting\nthe standalone admin layout.",
          "is_bot": false,
          "headline": "Add standalone pagination element to prevent style leakage.",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-28T14:11:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "885bfbc265ccbdb5e9710d59285cd9bf137d93aa",
          "body": "Extract flash rendering logic into flash/flash.php element for cleaner\nlayout code and easier maintenance.",
          "is_bot": false,
          "headline": "Refactor flash rendering to use dedicated element.",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-28T13:45:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2a133ce3f63a13dbd1d8d8ff00f9f207a4b29c77",
          "body": "Use inline flash rendering with consume() to avoid style leakage from\napp layouts and ensure messages are properly consumed from session.",
          "is_bot": false,
          "headline": "Fix flash message rendering in standalone layout.",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-28T13:39:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d827d343705eae34f975acc405382371548a267b",
          "body": null,
          "is_bot": false,
          "headline": "Add 'standalone-ui' to composer.json keywords",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-18T23:06:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a0b08c7fabab5dafd1e680f113ca1033bbe58951",
          "body": null,
          "is_bot": false,
          "headline": "Move Available Commands & Tasks to dedicated page in sidebar",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-18T22:52:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "70bedcc52ec3cd3c17e7098869520d383cd14cf3",
          "body": "* Add standalone admin layout with Bootstrap 5\n\nIntroduces a modern, self-contained admin dashboard similar to the\nQueue plugin. Features include:\n\n- QueueSchedulerAppController base controller with standalone mode\n- Self-contained Bootstrap 5 + Font Awesome 6 layout via CDN\n- Sidebar and mobile nav\n[…]\no have Bootstrap/Font Awesome configured.\n\n* Fix duplicate commands/tasks listing on add page\n\n* Replace quick_add with compact autocomplete search\n\n* Add type suffix to quick_add autocomplete options",
          "is_bot": false,
          "headline": "Add standalone admin layout with Bootstrap 5 (#21)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-18T21:37:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "271a6d648e63d76e6f736bb939c560a18800078e",
          "body": null,
          "is_bot": false,
          "headline": "Enable phpcs cache for faster subsequent runs",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-15T15:35:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "451f032107bc213f4f0770847e3aaa7c7097848a",
          "body": null,
          "is_bot": false,
          "headline": "Improve composer.json metadata",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-13T14:51:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4915828e034f76c0b52719be04a6c53c0ef62307",
          "body": null,
          "is_bot": false,
          "headline": "Add admin-panel keyword",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-13T14:43:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c01b3822bfbfbd0e1b5a59e58b668ba4cf098fe9",
          "body": null,
          "is_bot": false,
          "headline": "Fix Bootstrap collapse toggle for BS4/BS5 compatibility",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-03-09T23:43:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a3a4f4758b2babcd5fe6a9a6173d3ba2cd522b23",
          "body": null,
          "is_bot": false,
          "headline": "Fix PHPStan type error with entity annotation",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-02-28T00:02:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db34570e653420ca87bab61ea51ce89e28e51127",
          "body": null,
          "is_bot": false,
          "headline": "Fix phpunit",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-02-22T17:39:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "980f0c1ee6efede181c5097c897ba934cdecf57a",
          "body": null,
          "is_bot": false,
          "headline": "Allow PHPUnit 13",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-02-06T23:54:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2fc2741c944c51eeddd5b315cb231e796b291d2e",
          "body": null,
          "is_bot": false,
          "headline": "Upgrade migrations dev dep",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-31T04:15:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3304439c11f9a305ba74f410b2cb67c8c0fbd6a8",
          "body": "* Add content field autocomplete based on task type\n\nUses HTML5 datalist to suggest available Cake commands or Queue tasks\nin the content field on add/edit forms. The datalist switches\nautomatically based on the selected type dropdown.\n\nRefs #1\n\n* Improve autocomplete.\n\n* Improve autocomplete.",
          "is_bot": false,
          "headline": "Add content field autocomplete for available commands and tasks (#20)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-30T09:15:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8768ed06c688285ab996fb001c2797114dcf5e55",
          "body": "* Add scheduler logging and fix command output capture\n\nCommandExecuteTask now captures command stdout/stderr via temp file\nstreams and forwards the output through $this->io so the Processor's\noutput capture stores it in the queued_jobs output column. Previously\na fresh ConsoleIo was used, bypassing\n[…]\n.\n\n* Raise cakephp-queue minimum to ^8.9.0 for output capture support\n\nThe output capture feature (enableOutputCapture, getOutputAsText)\nwas added in 8.9.0 and is required for this PR's functionality.",
          "is_bot": false,
          "headline": "Add scheduler logging and fix command output capture (#19)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-30T03:33:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2bdb6b431e840454f4cff2dafa3d04b01aebfee3",
          "body": "Add direct job linking from scheduler to queue jobs",
          "is_bot": false,
          "headline": "Merge pull request #18 from dereuromark/feature/job-linking",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-29T10:37:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eb4bfed93ae9836e3fa48086ccfe5a856400d768",
          "body": null,
          "is_bot": false,
          "headline": "Update cakephp-queue version to ^8.1.0",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-28T05:13:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ca98fc421097ecb8ee869388d6fb8884ea036a6d",
          "body": null,
          "is_bot": false,
          "headline": "Raise PHP Min Version",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-28T05:02:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8638315e8c16f69e64962bfda30d7dae96354f33",
          "body": "Fix search filter parameter for Queue plugin",
          "is_bot": false,
          "headline": "Merge pull request #17 from dereuromark/feature/view-job-statistics",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-14T09:38:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d4ead1ce10a36e31d0103c0cc9916b500688b33a",
          "body": null,
          "is_bot": false,
          "headline": "Fix search filter parameter for Queue plugin",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-14T09:37:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "635ebd1c57b4bc71cb6db946d01ec18f1309e5e7",
          "body": "Add job statistics and queue link to scheduler row view",
          "is_bot": false,
          "headline": "Merge pull request #16 from dereuromark/feature/view-job-statistics",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-14T09:27:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d336103c784a63d9d62299aed4a6785789ad3dd0",
          "body": "- Display average, min, and max execution duration\n- Show total runs, completed, and failed counts\n- Add recent executions table with status and duration\n- Add quick link to view jobs in Queue backend\n- Use PHP-based duration calculation for database portability",
          "is_bot": false,
          "headline": "Add job statistics and recent executions to scheduler row view",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-14T09:20:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1e14730e97b855cb6a29b1f65f9b050b9f18d6d",
          "body": "Improve code documentation",
          "is_bot": false,
          "headline": "Merge pull request #15 from dereuromark/improve-docs",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-04T04:50:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a93bdcd9b9dd481aa50bca1e53edbdc5226deafa",
          "body": null,
          "is_bot": false,
          "headline": "Add PHPDoc to Scheduler class and methods",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-04T04:48:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "15220b8c1468354b2689f0ddbaf8b85c654170a7",
          "body": "Fix PHP version badge in README",
          "is_bot": false,
          "headline": "Merge pull request #14 from dereuromark/fix-readme-badge",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-04T04:40:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e30d7e942623412231d54269f86554d11c329b6",
          "body": null,
          "is_bot": false,
          "headline": "Fix PHP version badge in README",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-04T04:37:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "37ccfc60f4e21fd4a546b6866bf81c8ddfab70ee",
          "body": "Add missing command description for scheduler run",
          "is_bot": false,
          "headline": "Merge pull request #13 from dereuromark/add-command-descriptions",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-04T01:38:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e561789d0e743206538265368912c87598dd4764",
          "body": null,
          "is_bot": false,
          "headline": "Add missing command description for scheduler run",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-04T01:33:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c417a2a016887786c48dd7d2ac34250f16fb5c1e",
          "body": "Make Icon configuration optional with text fallback",
          "is_bot": false,
          "headline": "Merge pull request #12 from dereuromark/feature/optional-icon-config",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-01T18:21:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8b48627c268356751233e505507ce822d743a4a6",
          "body": "- Add Icon config to app.example.php\n- Document icon configuration in docs/README.md\n- Conditionally load Icon helper only when Icon.sets is configured\n- Add icon element with text fallback for when icons are not configured\n\nFixes #11",
          "is_bot": false,
          "headline": "Make Icon configuration optional with text fallback",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2026-01-01T16:35:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "edcf9c04d02184b7966c1c2705f7da527e4f3aab",
          "body": null,
          "is_bot": false,
          "headline": "Auto-fix CS - CS master branch",
          "author_name": "Mark",
          "author_login": "dereuromark",
          "committed_at": "2025-12-01T17:32:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8a6b85de4fd3987e8575c66b41e3709f74e50f02",
          "body": "- Add parameter and return type hints to Command classes\n- Add type hints to Controller action methods\n- Add type hints to Entity and Table validation methods\n- Add declare(strict_types=1) to files missing it\n- Add use statement for Response class\n- Update PHPDoc blocks to match type signatures\n- Ad\n[…]\nlicit return statements where needed\n\nAll tests, PHPStan Level 8, and PHPCS checks pass.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-authored-by: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add comprehensive type hints throughout codebase (#10)",
          "author_name": "Mark Scherer",
          "author_login": "dereuromark",
          "committed_at": "2025-11-19T15:36:14Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8eef9989d752ced68090ac3d95e4cf289dd01321",
          "body": "- Add parameter and return type hints to Command classes\n- Add type hints to Controller action methods\n- Add type hints to Entity and Table validation methods\n- Add declare(strict_types=1) to files missing it\n- Add use statement for Response class\n- Update PHPDoc blocks to match type signatures\n- Ad\n[…]\nlicit return statements where needed\n\nAll tests, PHPStan Level 8, and PHPCS checks pass.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add comprehensive type hints throughout codebase",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2025-11-19T13:59:53Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "555485c7ab73c04db100ec4e6a7be82e3501c7a3",
          "body": null,
          "is_bot": false,
          "headline": "Adjust phpcs config",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2025-11-17T09:52:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ac36d8eb56b2ee5237c9dc82866b0c7a4bd4ea8a",
          "body": null,
          "is_bot": false,
          "headline": "Fix docs",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2025-11-12T14:00:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5d23bdfb80d119d2ae6f6cbb9ee6ea9955ded948",
          "body": "Normalize @minutely to standard cron expression (* * * * *) before passing to CronExpression constructor to avoid InvalidArgumentException.\n\nThe @minutely shortcut is supported in the entity but not recognized by the dragonmantank/cron-expression library.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix @minutely cron expression handling in view template.",
          "author_name": "mscherer",
          "author_login": "dereuromark",
          "committed_at": "2025-11-08T11:40:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        }
      ],
      "releases_count": 26,
      "commits_last_year": 110,
      "latest_release_at": "2026-05-28T16:22:31Z",
      "latest_release_tag": "0.3.6",
      "releases_from_tags": false,
      "days_since_last_push": 30,
      "active_weeks_last_year": 29,
      "days_since_latest_release": 60,
      "mean_days_between_releases": 13.7
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 57,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "dereuromark/cakephp-queue-scheduler",
          "exists": true,
          "license": "MIT",
          "keywords": [
            "queue",
            "plugin",
            "cron",
            "cakephp",
            "automation",
            "admin-panel",
            "recurring",
            "scheduler",
            "standalone-ui"
          ],
          "ecosystem": "packagist",
          "matches_repo": true,
          "registry_url": "https://packagist.org/packages/dereuromark/cakephp-queue-scheduler",
          "is_deprecated": false,
          "latest_version": "0.3.6",
          "repository_url": "https://github.com/dereuromark/cakephp-queue-scheduler",
          "versions_count": 26,
          "total_downloads": 22287,
          "dependents_count": 1,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 4614,
          "first_published_at": null,
          "latest_published_at": "2026-05-28T16:13:03Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 60
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 7,
      "watchers": 1,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 1
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 34351,
      "source_files_sampled": 66,
      "oversized_source_files": 0,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "composer.json"
      ],
      "advisories": {
        "error": "No resolved dependencies carried a version and a supported ecosystem",
        "scope": "repository_graph",
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 10,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "packagist"
      ],
      "dependencies": [
        {
          "name": "cakephp/cakephp",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^5.1.1"
        },
        {
          "name": "dragonmantank/cron-expression",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^3.3"
        },
        {
          "name": "dereuromark/cakephp-tools",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^3.0.0"
        },
        {
          "name": "dereuromark/cakephp-queue",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "^8.9.0"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "cakephp/cakephp",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "dereuromark/cakephp-queue",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "dereuromark/cakephp-tools",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "dragonmantank/cron-expression",
            "direct": true,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "cakephp/migrations",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "dereuromark/cakephp-templating",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "fig-r/psr2r-sniffer",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "panlatent/cron-expression-descriptor",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "php",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "phpunit/phpunit",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 10,
        "direct_count": 4,
        "indirect_count": 6
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 38,
        "open_issues": 1,
        "closed_ratio": 0.857,
        "closed_issues": 6,
        "closed_unmerged_prs": 4
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "dereuromark",
          "commits": 186,
          "avatar_url": "https://avatars.githubusercontent.com/u/39854?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [
        "phpcs.xml",
        "phpstan.neon"
      ],
      "has_editorconfig": true,
      "has_linter_config": true,
      "has_precommit_config": false
    },
    "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": 1,
            "reason": "branch protection is not maximal on development and all release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 10,
            "reason": "15 out of 15 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": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 3 contributing companies or organizations -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 1 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": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "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": null,
            "reason": "No tokens found",
            "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": "6caadcf36793f03190eefc112c9391f9cb4e463d",
        "ran_at": "2026-07-28T09:47:28Z",
        "aggregate_score": 4.4,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-28T02:10:10Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-05-28T16:13:03Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 49,
          "created_at": "2026-07-16T11:25:12Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/dereuromark/cakephp-queue-scheduler",
    "host": "github.com",
    "name": "cakephp-queue-scheduler",
    "owner": "dereuromark"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 65,
      "inputs": {
        "security": 44,
        "vitality": 86,
        "community": 42,
        "governance": 62,
        "engineering": 84
      },
      "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": 110,
              "human_commit_share": 1,
              "days_since_last_push": 30,
              "active_weeks_last_year": 29
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 30 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "29/52 weeks with commits",
                "points": 20.1,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 29
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "110 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 110
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 1 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": 26,
              "latest_release_tag": "0.3.6",
              "releases_from_tags": false,
              "days_since_latest_release": 60,
              "mean_days_between_releases": 13.7
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "26 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 26
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 60 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 60
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~13.7 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 13.7
                    }
                  }
                ],
                "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": 30,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 30 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 30
                    }
                  }
                ],
                "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": 42,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 13,
            "inputs": {
              "forks": 0,
              "stars": 7,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "7 stars",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "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": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 70,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": null,
            "notes": [],
            "value": 51,
            "inputs": {
              "packages": [
                "dereuromark/cakephp-queue-scheduler"
              ],
              "dependents": 1,
              "ecosystems": "packagist",
              "total_downloads": 22287,
              "monthly_downloads": 4614
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "4,614 downloads/month across packagist",
                "points": 48.9,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 4614,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "1 packages depend on it",
                "points": 2,
                "status": "partial",
                "details": [
                  {
                    "code": "registry_dependents",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 62,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 20,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 3 contributing companies or organizations -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "merged_prs": 38,
              "open_issues": 1,
              "closed_issues": 6,
              "issue_closed_ratio": 0.857,
              "closed_unmerged_prs": 4
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "86% of issues closed",
                "points": 40.1,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 86
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "38/42 decided PRs merged",
                "points": 34.6,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 38,
                      "decided": 42
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "good",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 70,
            "inputs": {
              "followers": 750,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "dereuromark",
              "public_repos": 123,
              "account_age_days": 6437
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "750 followers of dereuromark",
                "points": 20.7,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 750,
                      "login": "dereuromark"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "123 public repos, account ~17 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 123
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 17
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "dereuromark/cakephp-queue-scheduler"
              ],
              "ecosystems": "packagist",
              "any_deprecated": false,
              "min_days_since_publish": 60
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on packagist",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 60 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 60
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "26 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 26
                    }
                  }
                ],
                "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": 84,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "excellent",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "1 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "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": "phpcs.xml, phpstan.neon",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "phpcs.xml, phpstan.neon"
                    }
                  }
                ],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "15 out of 15 merged PRs checked by a CI test -- score normalized to 10",
                "points": 20,
                "status": "met",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "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": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 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": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 44,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 44,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 13,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 5,
              "scorecard_aggregate": 4.4
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 0.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "15 out of 15 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 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 3 contributing companies or organizations -- score normalized to 10",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 1 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 not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "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": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 3
            },
            "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": "at_risk",
        "name": "AI Readiness",
        "value": 43,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 37,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.7,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "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": "70 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 37.3,
                "status": "partial",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 70,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 43,
            "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.03,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": "phpcs.xml, phpstan.neon",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "phpcs.xml, phpstan.neon"
                    }
                  }
                ],
                "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": "3 of the last 100 commits agent-authored or agent-credited",
                "points": 6,
                "status": "partial",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 3,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "primary_language": "PHP",
              "largest_source_bytes": 34351,
              "source_files_sampled": 66,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "PHP without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "PHP"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/66 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 66,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "No resolved dependencies carried a version and a supported ecosystem"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-28T09:47:39.444648Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/d/dereuromark/cakephp-queue-scheduler.svg",
  "full_name": "dereuromark/cakephp-queue-scheduler",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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