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

yourtablecloth / TableCloth

식탁보 프로젝트

C#AGPL-3.0★ 1096 estrellas⑂ 60 forksdesde jul 2021Ver en GitHub ↗

yourtablecloth/TableCloth tiene un índice de salud de 64 sobre 100, lo que lo sitúa en la banda Moderado. Su puntuación más alta es Vitality (80/100) y la más baja, AI Readiness (48/100). Se actualizó por última vez hace 1 día. Una sola persona concentra la mayor parte del trabajo reciente.

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

64
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

39 seguidores16 repositorios públicosdesde ago 2021

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

Métricas por categoría

Vitalidad

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

80Bueno · 22% del índice global
Cómo se puntúa
36/36Recencia de push — último push hace 1 días
10.4/36Cadencia de commits — 15/52 semanas con commits
18/18Volumen de commits — 298 commits en el último año
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
Datos de entrada utilizados
commits_last_year298
human_commit_share0,92
days_since_last_push1
active_weeks_last_year15
Cómo se puntúa
27/27Publica versiones — 31 versiones publicadas
36/36Recencia de las versiones — última versión hace 6 días
27/27Cadencia de publicación — una versión cada ~21,9 días
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Datos de entrada utilizados
releases_count31
latest_release_tagv1.20.6
releases_from_tagsno
days_since_latest_release6
mean_days_between_releases21,9

Comunidad y Adopción

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

60Moderado · 18% del índice global
Cómo se puntúa
49.3/60Estrellas — 1096 estrellas
14.8/25Forks — 60 forks
5/15Observadores — 9 observadores
Datos de entrada utilizados
forks60
stars1096
watchers9
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Cómo se puntúa
22.5/22.5README
22.5/22.5Licencia — licencia reconocida (AGPL-3.0)
0/18Guía CONTRIBUTING
0/13.5Código de conducta
0/7.2Plantilla de issues
0/6.3Plantilla de PR
Datos de entrada utilizados
has_readme
has_license
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno

Sostenibilidad y Gobernanza

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

57Moderado · 24% del índice global
Cómo se puntúa
9/54Factor bus — la mitad de los commits recae en 1 contribuyente(s)
1/22.5Distribución de commits — el principal contribuyente firma el 96% de los commits
13.5/13.5Amplitud de contribuyentes — 14 contribuyentes
10/10OpenSSF Scorecard: Contributors — project has 7 contributing companies or organizations
Datos de entrada utilizados
bus_factor1
contributors_sampled14
top_contributor_share0,957
Cómo se puntúa
46.5/46.8Resolución de issues — 100% de issues cerradas
35.7/38.3Aceptación de PR — 57/61 PR decididos fusionados
0/15OpenSSF Scorecard: Code-Review — Found 0/11 approved changesets -- score normalized to 0
Datos de entrada utilizados
merged_prs57
open_issues1
closed_issues199
issue_closed_ratio0,995
closed_unmerged_prs4
Cómo se puntúa
30/30Respaldo de la propiedad — propiedad de una organización
0/20Dominio verificado
11.5/25Alcance del propietario — 39 seguidores de yourtablecloth
18.8/25Trayectoria — 16 repos públicos, cuenta de ~4 años
Datos de entrada utilizados
followers39
owner_typeOrganization
is_verified
owner_loginyourtablecloth
public_repos16
account_age_days1798

Calidad de Ingeniería

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

60Moderado · 20% del índice global
Cómo se puntúa
24/24Flujos de trabajo de CI — 4 flujo(s) de trabajo
0/24Pruebas presentes
0/16Configuración de linter
0/9.6Hooks de pre-commit
6.4/6.4.editorconfig
20/20OpenSSF Scorecard: CI-Tests — 14 out of 14 merged PRs checked by a CI test -- score normalized to 10
Datos de entrada utilizados
has_ci
has_testsno
has_editorconfig
has_linter_configno
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
10/10Topics — 6 topics
0/10Wiki
Datos de entrada utilizados
topicshacktoberfest, csharp, dotnet, sdk, windows-10, windows-11
has_wikino
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?

60Moderado · 16% del índice global
Cómo se puntúa
7.5/7.5Binary-Artifacts — no binaries found in the repo
2.2/7.5Branch-Protection — branch protection is not maximal on development and all release branches
2.5/2.5CI-Tests — 14 out of 14 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/11 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 7 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Licencia — license file detected
7.5/7.5Maintained — 30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — sin datos
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
5/5SAST — SAST tool is run on all commits
5/5Security-Policy — security policy file detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Datos de entrada utilizados
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate6
Excluidos de la puntuación (sin datos o no aplicable): packaging. 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.

48En 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)
40/40Historial de commits legible — 92 de 92 commits humanos declaran su intención (asunto estructurado o cuerpo explicativo)
Datos de entrada utilizados
has_llms_txtno
legible_history_share1
agent_instruction_files
agent_instruction_max_bytes
Cómo se puntúa
12.6/18Arranque con un solo comando — src/Spork.App/Spork.App.csproj, src/Spork.Bootstrapper/Spork.Bootstrapper.csproj, src/Spork.Sandbox/Spork.Sandbox.csproj (convención del toolchain, sin ejecutor de tareas)
0/22Pruebas automatizadas
0/11Configuración de lint / formato
11/11Verificación estática de tipos — C# (tipado estático)
0/10Entorno reproducible
10/10Práctica demostrada con agentes — 86 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 — dependency not pinned by hash detected -- score normalized to 0
Datos de entrada utilizados
has_nixno
has_testsno
lockfiles
has_dockerfileno
typed_language
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0,86
toolchain_manifestssrc/Spork.App/Spork.App.csproj, src/Spork.Bootstrapper/Spork.Bootstrapper.csproj, src/Spork.Sandbox/Spork.Sandbox.csproj, src/Spork.Test/Spork.Test.csproj, src/Spork/Spork.csproj, src/TableCloth.App/TableCloth.App.csproj, src/TableCloth.Core/TableCloth.Core.csproj, src/TableCloth.Test/TableCloth.Test.csproj, src/TableCloth/TableCloth.csproj
dependency_bot_commit_share0
Cómo se puntúa
45/45Código verificable por tipos — C# (tipado estático)
54.8/55Tamaños de archivo manejables — 1/260 archivos fuente de más de 60 KB
Datos de entrada utilizados
primary_languageC#
largest_source_bytes88.947
source_files_sampled260
oversized_source_files1

Datos clave

1096estrellas de GitHub
14contribuidores
298commits en los últimos 12 meses
1días desde el último push
31versiones publicadas
1factor bus
1issues abiertas
ecosistemas 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

Historial de estrellas y forks 0 ★ / 60 ⇿
0Estrellas
60Forks
24Versiones

Cuándo se añadió cada estrella y fork, recopilado de GitHub y agrupado por día. El crecimiento acumulado se sitúa justo encima de las adiciones diarias que lo componen, de modo que ambos se leen en conjunto: la acumulación orgánica sostenida no se parece en nada a un pico abrupto y efímero. Cuando esa diferencia es medible, se informa como autenticidad del crecimiento.

01020304050606072021-072023-122026-05
Mayor 0Menor 7Parche 17

Cada punto abarca 5 días.

OpenSSF Scorecard 6.0 / 10
6.0agregado

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-25 00:19 UTC

10Binary-Artifactsno binaries found in the repo
3Branch-Protectionbranch protection is not maximal on development and all release branches
10CI-Tests14 out of 14 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/11 approved changesets -- score normalized to 0
10Contributorsproject has 7 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 30 issue activity found in the last 90 days -- score normalized to 10
n/dPackagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
10SASTSAST tool is run on all commits
10Security-Policysecurity policy file detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
Dependencias directas 52
RegistroPaqueteRestricción de versiónManifiesto
NuGetAsyncAwaitBestPractices.MVVMsrc/Spork.App/Spork.App.csproj
NuGetCommunityToolkit.Mvvmsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Configurationsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Configuration.Bindersrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Configuration.CommandLinesrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Configuration.EnvironmentVariablessrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Configuration.Jsonsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Configuration.UserSecretssrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.DependencyInjectionsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Hostingsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Httpsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Loggingsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Logging.Consolesrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Logging.Debugsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.Logging.EventLogsrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Xaml.Behaviors.Wpfsrc/Spork.App/Spork.App.csproj
NuGetSentrysrc/Spork.App/Spork.App.csproj
NuGetSentry.Serilogsrc/Spork.App/Spork.App.csproj
NuGetSerilogsrc/Spork.App/Spork.App.csproj
NuGetSerilog.Extensions.Loggingsrc/Spork.App/Spork.App.csproj
NuGetSystem.CommandLinesrc/Spork.App/Spork.App.csproj
NuGetMicrosoft.Extensions.DependencyInjectionsrc/Spork.Sandbox/Spork.Sandbox.csproj
NuGetMicrosoft.Extensions.Hostingsrc/Spork.Sandbox/Spork.Sandbox.csproj
NuGetMicrosoft.Extensions.Loggingsrc/Spork.Sandbox/Spork.Sandbox.csproj
NuGetMicrosoft.NET.Test.Sdk18.0.1src/Spork.Test/Spork.Test.csproj
NuGetMSTest.TestAdapter4.0.2src/Spork.Test/Spork.Test.csproj
NuGetMSTest.TestFramework4.0.2src/Spork.Test/Spork.Test.csproj
NuGetMicrosoft.Extensions.DependencyInjectionsrc/Spork/Spork.csproj
NuGetMicrosoft.Extensions.Hostingsrc/Spork/Spork.csproj
NuGetSentrysrc/Spork/Spork.csproj
NuGetAsyncAwaitBestPractices.MVVMsrc/TableCloth.App/TableCloth.App.csproj
NuGetMicrosoft.Extensions.DependencyInjectionsrc/TableCloth.App/TableCloth.App.csproj
NuGetMicrosoft.Extensions.Hostingsrc/TableCloth.App/TableCloth.App.csproj
NuGetMicrosoft.Extensions.Httpsrc/TableCloth.App/TableCloth.App.csproj
NuGetMicrosoft.Xaml.Behaviors.Wpfsrc/TableCloth.App/TableCloth.App.csproj
NuGetPnPeople.Securitysrc/TableCloth.App/TableCloth.App.csproj
NuGetSentry.Serilogsrc/TableCloth.App/TableCloth.App.csproj
NuGetSerilog.Extensions.Loggingsrc/TableCloth.App/TableCloth.App.csproj
NuGetSerilog.Sinks.Filesrc/TableCloth.App/TableCloth.App.csproj
NuGetSystem.CommandLinesrc/TableCloth.App/TableCloth.App.csproj
NuGetSystem.Managementsrc/TableCloth.App/TableCloth.App.csproj
NuGetVelopacksrc/TableCloth.App/TableCloth.App.csproj
NuGetXamlRadialProgressBarsrc/TableCloth.App/TableCloth.App.csproj
NuGetCommunityToolkit.Mvvmsrc/TableCloth.Core/TableCloth.Core.csproj
NuGetSystem.Security.AccessControlsrc/TableCloth.Core/TableCloth.Core.csproj
NuGetSystem.Text.Jsonsrc/TableCloth.Core/TableCloth.Core.csproj
NuGetMicrosoft.NET.Test.Sdk18.0.1src/TableCloth.Test/TableCloth.Test.csproj
NuGetMSTest.TestAdapter4.0.2src/TableCloth.Test/TableCloth.Test.csproj
NuGetMSTest.TestFramework4.0.2src/TableCloth.Test/TableCloth.Test.csproj
NuGetMicrosoft.Extensions.DependencyInjectionsrc/TableCloth/TableCloth.csproj
NuGetMicrosoft.Extensions.Hostingsrc/TableCloth/TableCloth.csproj
NuGetVelopacksrc/TableCloth/TableCloth.csproj
Todas las dependencias 28

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

RegistroPaqueteVersiónRelación
NuGetAsyncAwaitBestPractices.MVVMdirecta
NuGetCommunityToolkit.Mvvmdirecta
NuGetMicrosoft.Extensions.Configurationdirecta
NuGetMicrosoft.Extensions.Configuration.Binderdirecta
NuGetMicrosoft.Extensions.Configuration.CommandLinedirecta
NuGetMicrosoft.Extensions.Configuration.EnvironmentVariablesdirecta
NuGetMicrosoft.Extensions.Configuration.Jsondirecta
NuGetMicrosoft.Extensions.Configuration.UserSecretsdirecta
NuGetMicrosoft.Extensions.DependencyInjectiondirecta
NuGetMicrosoft.Extensions.Hostingdirecta
NuGetMicrosoft.Extensions.Httpdirecta
NuGetMicrosoft.Extensions.Loggingdirecta
NuGetMicrosoft.Extensions.Logging.Consoledirecta
NuGetMicrosoft.Extensions.Logging.Debugdirecta
NuGetMicrosoft.Extensions.Logging.EventLogdirecta
NuGetMicrosoft.Xaml.Behaviors.Wpfdirecta
NuGetPnPeople.Securitydirecta
NuGetSentrydirecta
NuGetSentry.Serilogdirecta
NuGetSerilogdirecta
NuGetSerilog.Extensions.Loggingdirecta
NuGetSerilog.Sinks.Filedirecta
NuGetSystem.CommandLinedirecta
NuGetSystem.Managementdirecta
NuGetSystem.Security.AccessControldirecta
NuGetSystem.Text.Jsondirecta
NuGetVelopackdirecta
NuGetXamlRadialProgressBardirecta
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": [
        "hacktoberfest",
        "csharp",
        "dotnet",
        "sdk",
        "windows-10",
        "windows-11"
      ],
      "is_fork": false,
      "size_kb": 12146,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "C#": 891493,
        "HTML": 13470,
        "Batchfile": 52,
        "PowerShell": 14428
      },
      "pushed_at": "2026-07-23T14:08:31Z",
      "created_at": "2021-07-14T13:35:31Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-23T14:10:42Z",
      "description": "식탁보 프로젝트",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "AGPL-3.0",
      "default_branch": "main",
      "license_spdx_raw": "AGPL-3.0",
      "primary_language": "C#",
      "significant_languages": [
        "C#"
      ]
    },
    "owner": {
      "blog": "https://yourtablecloth.app",
      "name": "식탁보 프로젝트",
      "type": "Organization",
      "login": "yourtablecloth",
      "company": null,
      "location": "Korea, South",
      "followers": 39,
      "avatar_url": "https://avatars.githubusercontent.com/u/89287245?v=4",
      "created_at": "2021-08-21T03:20:34Z",
      "is_verified": null,
      "public_repos": 16,
      "account_age_days": 1798
    },
    "license": {
      "state": "standard",
      "spdx_id": "AGPL-3.0",
      "raw_spdx": "AGPL-3.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.20.6",
          "kind": "patch",
          "published_at": "2026-07-18T09:37:50Z"
        },
        {
          "tag": "v1.20.5",
          "kind": "patch",
          "published_at": "2026-07-05T10:45:23Z"
        },
        {
          "tag": "v1.20.4",
          "kind": "patch",
          "published_at": "2026-07-03T12:06:01Z"
        },
        {
          "tag": "v1.20.3",
          "kind": "patch",
          "published_at": "2026-07-01T05:50:49Z"
        },
        {
          "tag": "v1.20.2",
          "kind": "patch",
          "published_at": "2026-06-30T10:35:37Z"
        },
        {
          "tag": "v1.20.1",
          "kind": "patch",
          "published_at": "2026-06-23T11:59:29Z"
        },
        {
          "tag": "v1.20.0",
          "kind": "minor",
          "published_at": "2026-06-22T13:50:48Z"
        },
        {
          "tag": "v1.16.3",
          "kind": "patch",
          "published_at": "2026-01-28T03:41:37Z"
        },
        {
          "tag": "v1.16.2",
          "kind": "patch",
          "published_at": "2026-01-07T01:48:56Z"
        },
        {
          "tag": "v1.16.1",
          "kind": "patch",
          "published_at": "2026-01-02T13:45:34Z"
        },
        {
          "tag": "v1.16.0",
          "kind": "minor",
          "published_at": "2025-12-31T15:36:56Z"
        },
        {
          "tag": "v1.15.0",
          "kind": "minor",
          "published_at": "2025-12-29T07:19:06Z"
        },
        {
          "tag": "v1.14.0",
          "kind": "minor",
          "published_at": "2024-12-04T13:08:26Z"
        },
        {
          "tag": "v1.13.2",
          "kind": "patch",
          "published_at": "2024-05-13T06:30:26Z"
        },
        {
          "tag": "v1.13.1",
          "kind": "patch",
          "published_at": "2024-04-16T01:54:45Z"
        },
        {
          "tag": "v1.13.0",
          "kind": "minor",
          "published_at": "2024-04-05T08:10:31Z"
        },
        {
          "tag": "v1.12.3",
          "kind": "patch",
          "published_at": "2024-02-07T04:59:39Z"
        },
        {
          "tag": "v1.12.2",
          "kind": "patch",
          "published_at": "2024-02-02T13:48:10Z"
        },
        {
          "tag": "v1.12.1",
          "kind": "patch",
          "published_at": "2024-01-28T07:20:48Z"
        },
        {
          "tag": "v1.12.0",
          "kind": "minor",
          "published_at": "2024-01-25T14:12:30Z"
        },
        {
          "tag": "v1.9.1",
          "kind": "patch",
          "published_at": "2023-09-03T12:53:11Z"
        },
        {
          "tag": "v1.9.0",
          "kind": "minor",
          "published_at": "2023-09-03T08:10:16Z"
        },
        {
          "tag": "v0.5.8",
          "kind": "patch",
          "published_at": "2023-07-17T13:51:27Z"
        },
        {
          "tag": "v0.5.7",
          "kind": "patch",
          "published_at": "2023-07-12T14:38:56Z"
        },
        {
          "tag": "v0.5.6",
          "kind": "patch",
          "published_at": "2023-07-11T13:53:10Z"
        },
        {
          "tag": "v0.5.5",
          "kind": "patch",
          "published_at": "2022-09-06T16:14:52Z"
        },
        {
          "tag": "v0.5.4",
          "kind": "patch",
          "published_at": "2022-03-09T20:47:18Z"
        },
        {
          "tag": "v0.5.3",
          "kind": "patch",
          "published_at": "2022-02-23T15:11:37Z"
        },
        {
          "tag": "v0.5.2",
          "kind": "patch",
          "published_at": "2021-11-16T15:27:55Z"
        },
        {
          "tag": "v0.5.1",
          "kind": "patch",
          "published_at": "2021-08-28T16:52:06Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2021-08-21T03:47:08Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "6da57ba1235135bdac9c7c4f8bd1689e0208a62c",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump TableClothCatalog submodule (7e3e6a8 → debe16d)",
          "author_name": "rkttu",
          "author_login": "rkttu",
          "committed_at": "2026-07-23T14:08:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "316e49975f46ea09858f4aa3b8da24860e85a309",
          "body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): 1.20.6",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-18T09:09:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cb1cd54c9fe595626200869704aeb70eb41cc80d",
          "body": "항목 수 증가에 대응해 사이트 탭과 동일한 방식의 키워드 검색을 보조\n프로그램(Companion) 탭에 추가. CatalogCompanion.IsMatchedItem 으로 표시\n이름·URL·아이디·설치 인자를 대소문자 무시 OR 매칭하며, 전용 검색어\n프로퍼티(CompanionSearchKeyword)와 CollectionView 필터로 연결한다.\n워터마크 예시는 목록 성격에 맞게(zip/drive) 별도 리소스로 분리했다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): 보조 프로그램 카탈로그에 키워드 검색 추가",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-18T09:08:46Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "95ded0975256ae5cd529ab3d8b945b2d84eb220e",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump TableClothCatalog submodule (3666154 → 7e3e6a8)",
          "author_name": "rkttu",
          "author_login": "rkttu",
          "committed_at": "2026-07-18T07:52:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fb6fff5eb78c2546f0fa56a371f737d3f87247a8",
          "body": "일시적 실패 재시도 로직의 분류 정확도를 높이고, \"재시도하지 않을 종류가 실제로\n재시도되지 않는지\"를 루프 동작 수준까지 검증한다.\n\n분류기(StepsPlayer.IsTransientDownloadException)\n- 소켓 수준 오류를 명시적으로 처리: 래핑되지 않은 SocketException도 일시적으로 취급\n  (HttpClient는 보통 HttpRequestException[StatusCode 없음]/IOException으로 래핑하지만,\n   다른 다운로드 계층 대비).\n- 상태 코드 기준 실패 판정을 정밀화: 기존 \"모\n[…]\nlayerRetryLoopTests: 실제 재시도 루프 시도 횟수 검증 — 영구성 코드/비일시적\n  예외는 1회(재시도 없음), 일시적 오류는 최대 3회, 중간 성공 시 즉시 중단.\n\n빌드 경고 0, Spork.Test 42개 통과.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "test(spork): 다운로드 재시도 분류 정밀화 + 소켓/상태코드/루프 검증 보강 (#300)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-09T13:47:09Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "57f2ee0462facc17304f18e689bab0e26ddbce2e",
          "body": null,
          "is_bot": true,
          "headline": "chore(spork): polish retry cancellation and status checks",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-09T13:47:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b0b419e3aceeb2acca849a4f6d8fbd6a88bacce0",
          "body": null,
          "is_bot": true,
          "headline": "feat(spork): retry transient download failures with backoff",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-09T13:47:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "14b6923ee33565a0a41ac9c32ee07d14cadb5ea1",
          "body": null,
          "is_bot": true,
          "headline": "Clarify Local Network Access policy version comment",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-09T12:04:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c36fc621abe09e1b1187706a21c7a8eb624fbd18",
          "body": "…#294)",
          "is_bot": true,
          "headline": "Auto-allow Local Network Access permission in sandbox startup (issue …",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-09T12:04:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "56af40f377d7a91cc6dcdf494dd7766fad29f5ae",
          "body": "전원 프로필 \"이름(고성능 GUID)\" 매칭은 복제/OEM 계획을 오탐하고 AC의 균형 조정처럼\n실제로는 100%로 동작하는 경우도 잘못 경고했다. 실제 성능에 직접적인 CPU 최대 성능 상한\n(최대 프로세서 상태)을 읽어 판정하도록 바꾸고, 안내도 전용 창으로 친절하게 재구성한다.\n\n판정 (Helpers)\n- IsHighPerformancePowerScheme(이름 매칭) 제거. 현재 전원 소스(AC/DC)에 적용되는\n  최대 프로세서 상태(GUID_PROCESSOR_THROTTLE_MAXIMUM)를 PowerReadAC/DCVa\n[…]\ntrings.Info_Sandbox_ProcessorThrottled 제거, UIStringResources에 PowerSchemeGuide_* 추가(한/영).\n\n빌드 경고 0, 테스트 통과, 스로틀 시뮬레이션·스모크 실행으로 검증.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(power): 전원 성능 안내를 실제 CPU 상한 기반 판정 + 전용 창으로 개선 (#295)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-08T14:57:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c3c2adae0855616e33296d334692235a9ae6a744",
          "body": "…e GUID",
          "is_bot": true,
          "headline": "Use type-safe Marshal.PtrToStructure generic overload for power schem…",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-08T14:57:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c7ebba03537a38252b451db21b2beca0c0292f26",
          "body": "…unch",
          "is_bot": true,
          "headline": "Warn when host power scheme is not high performance before Sandbox la…",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-08T14:57:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2773b207474f7d7255bb0a6f0fce55e162458675",
          "body": "호스트 보안 프로그램 대응 등으로 호환성 설정이 계속 늘어날 것을 대비해,\n하드코딩된 체크박스 3개를 데이터 기반 구조로 전환한다.\n\n- CompatibilityOptionItem: 기존 [ObservableProperty] bool을 그대로 읽고 쓰는 얇은\n  어댑터. 이름·설명(한/영)을 합친 검색 인덱스와 MatchesFilter를 보유. 저장\n  파이프라인(OnViewModelPropertyChangedAsync)은 변경 없이 재사용된다.\n- OptionsWindowViewModel: CompatibilityOptions 컬\n[…]\nPlaceholder / _NoSearchResults (한/영).\n- 테스트: 검색/필터/대소문자·한영 매칭/결과 없음/양방향 바인딩 및 로드 시점\n  IsChecked 알림까지 검증(8건).\n\n빌드 경고 0, 테스트 54건 통과.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(options): 호환성 탭에 설정 검색 + 수직 스크롤 도입",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-08T13:43:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9675910e5672afa45e3774465e622b12abb0c2c7",
          "body": "리뷰에서 지적된 잔여 개선 사항 반영:\n- SandboxBuilder(호스트): LocalMachine\\Root 열거 인증서 중 미매칭은 즉시,\n  매칭분은 PEM 추출 후 finally에서 Dispose (X509Certificate2 키 핸들 누수 방지).\n- SandboxBootstrap(게스트): CurrentUser\\Root 등록 후 X509Certificate2Collection\n  항목을 finally에서 Dispose (Store.Add는 복제하므로 원본 해제 안전).\n- git SChannel 구성: WaitForExit 타임아웃(5s) 시 Kill(entireProcessTree)로\n  좀비 프로세스 방지.\n\n동작 변화 없음(정리 전용). 빌드 경고 0, TableCloth.Test 46 + Spork.Test 3 통과.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(zscaler): 인증서 전파 리소스 정리 (#292 후속)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-08T13:43:50Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c714c903a0c646546772f14d02e08afc89a77d24",
          "body": null,
          "is_bot": true,
          "headline": "Reduce git schannel config timeout to 5s during sandbox boot",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-08T13:43:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8a37458c6c4bec31767a82f9fee32d86f009fd1",
          "body": null,
          "is_bot": true,
          "headline": "Add ZScaler root cert propagation option (#292)",
          "author_name": "copilot-swe-agent[bot]",
          "author_login": "Copilot",
          "committed_at": "2026-07-08T13:43:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f9f875ea72c5a0dffeea639251a02010533bdcc5",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump TableClothCatalog submodule (37cb722 → 3666154)",
          "author_name": "rkttu",
          "author_login": "rkttu",
          "committed_at": "2026-07-06T14:46:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f63b7bf822df977470728c911fc822e929cfcc08",
          "body": "Windows PowerShell 5.1 은 IWR 진행률 렌더링이 전송 자체를 크게 늦추는 특성이\n있다. 런처(약 5MB)는 소용량이라 단계 메시지([1/2]/[2/2])로 충분하고, 진짜\n진행률 UX(약 90MB 식탁보 다운로드)는 런처 GUI 가 담당하므로 준비 단계의\n바이트 진행률은 불필요하다.\n\n- tablecloth-prepare.ps1: $ProgressPreference = 'SilentlyContinue' 명시\n  (세션 기본이 Continue 라 줄 제거가 아니라 명시 설정이어야 함). 사유 주석.\n- .wsb 주석/SPEC §0.5/설계 §11 동기화 + SPEC 변경 이력.\n\n검증: 두 파일 ASCII-only, ps1 구문 OK, XML OK(LogonCommand 불변).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(no-install): 준비 스크립트의 IWR 바이트 진행률 끔 (5.1 렌더링 페널티 회피)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T13:02:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "721a1ed218d2ddae63dcc469a266f0f7bdf42c19",
          "body": "준비 스크립트 실행을 임시 파일 + dot-source 에서 Chocolatey install 관용구인\niex ((New-Object Net.WebClient).DownloadString(url)) 무파일 실행으로 전환한다.\n\n- TLS 1.2 보정([Net.ServicePointManager]::SecurityProtocol -bor 3072) 추가\n  (.wsb 인라인 + ps1 양쪽, Chocolatey 검증 관용구).\n- -NoExit 제거: iex 는 세션 스코프 실행이라 준비 스크립트의 exit 가 곧 창 닫기.\n  명령\n[…]\n 마커 기록, 프로세스 종료=창 닫힘),\n(2) DownloadString 실패가 catch 에 잡힘(exitcode 42) 확인.\n정적: 두 파일 ASCII-only, ps1/외부/내부/SPEC 예시 구문 파서 OK, XML OK.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(no-install): Chocolatey식 iex 부트스트랩 + 완료 시 창 자동 종료",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T12:40:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bd2f55724ac2a5997b46263a1ed35d683ea32a79",
          "body": "샌드박스 실물 테스트에서 tablecloth-prepare.ps1 의 한글이 모지바케로 깨져\n파싱 자체가 실패했다(스크린샷 실측). 원인: Windows PowerShell 5.1 은 BOM 없는\n스크립트를 레거시 ANSI 코드페이지로 읽는데, 리포 파일은 BOM 없는 UTF-8 이고\n게스트 코드페이지는 호스트 언어팩에 따라 달라진다.\n\n- no-install-spork.wsb / tablecloth-prepare.ps1: 주석·표시 문자열 포함 전체를\n  영문 ASCII 전용으로 전환(ASCII 는 모든 코드페이지에서 동일 바이트\n[…]\nSCII 전용) 명문화 + 예시 동기화 +\n  변경 이력.\n\n검증: 두 파일 ASCII-only 바이트 검사 통과, CP949 오해석 시뮬레이션에서 UTF-8\n해석과 동일 확인, ps1/외부/내부 명령 구문 파서 OK, XML OK.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(no-install): .wsb/준비 스크립트 전체를 ASCII 전용(영문)으로 전환",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T12:11:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e7df1ebe5b9386b75c1cf77f3d742236b9cd1eea",
          "body": ".wsb 인라인에 준비 스크립트 전문(문자열 배열, 약 2,400자)을 내장하던 것을\ntools/no-install/tablecloth-prepare.ps1 리포 파일 + 릴리스 자산(고정 URL)으로\n분리한다. LogonCommand 는 782자로 축소.\n\n- .wsb: 보이는 창(-WindowStyle Normal, -NoExit) 기동 → 제목/안내 → DNS 프로브\n  (닭-달걀로 인라인 잔류) → ps1 을 latest/download 고정 URL 로 다운로드 →\n  dot-source 실행만 남는 소형 포인터.\n- tab\n[…]\n화. Base64 배제 원칙 유지.\n\n검증: prepare.ps1/외부/내부 명령 구문 파서 OK, 한글 무결성 OK, XML/YAML OK,\nbuild.cs 파싱 OK. 실제 창 표시는 자산 포함 릴리스 게시 후 샌드박스에서 확인.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(no-install): LogonCommand 축소 — 준비 로직을 릴리스 자산 ps1로 분리",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T11:59:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8afec30d9ea7f7d67677085d0964599543e133f5",
          "body": "WSB 는 LogonCommand 의 콘솔 창 자체를 숨긴 채 실행하므로(실측), 직전 커밋의\n\"같은 콘솔에 출력\" 방식은 사용자에게 보이지 않아 무효였다.\n\n- 숨은 셸이 준비 스크립트(tablecloth-prepare.ps1)를 임시 폴더에 평문으로 쓴 뒤,\n  Start-Process -WindowStyle Normal 로 새 보이는 PowerShell 창을 띄워 그 안에서\n  안내 메시지 + DNS 프로브 + 런처 다운로드(진행 막대)를 수행한다.\n- 다운로드 실패 시 오류를 붉게 표시하고 Read-Host 로 창을 유지한다\n[…]\nC §0.5 예시/규약/변경이력 동기화.\n\n검증: XML 파싱 OK, 외부/생성 스크립트 구문 파서 OK, 한글 무결성 OK\n(Set-Content 부분 실제 실행으로 생성 파일 확인). 실제 창 표시는 샌드박스에서\n최종 확인 필요.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(no-install): 준비 표시를 새 보이는 PowerShell 창으로 (WSB 콘솔 숨김 대응)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T11:59:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "5b65808a879af96312de5705fc3e938e650c3d4a",
          "body": "콜드부팅 후 런처 GUI 가 뜨기 전, LogonCommand 가 숨은 채 다운로드만 하던 빈 화면\n구간을 없앤다. 새 다운로드 UI 를 만들면 같은 빈 구간이 반복되므로, 이미 실행 중인\nPowerShell 콘솔을 재사용한다.\n\n- 창 제목('식탁보 준비') + 단계별 안내 메시지([1/3]~[3/3]).\n- $ProgressPreference='Continue' 로 런처 다운로드 진행 막대 표시.\n- 런처 실행 후 Start-Sleep 1s 로 GUI 인계까지 잔상 유지 후 콘솔 자동 종료.\n- WindowTitle 설정은 try/catch 로 가드(콘솔 없을 때 안전).\n- SPEC §0.5 예시 동기화 + 콜드부팅 피드백 규약 문서화.\n\nXML/PowerShell 구문 검증 통과.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(no-install): .wsb 콜드부팅 시 보이는 콘솔 + 진행 표시",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T11:59:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a77158cdd1f05237c6c22e157b64f215db72345a",
          "body": "무설치 런처(Spork.Bootstrapper) 정식 데뷔 + 고정 URL 자산, DNS probe-then-fallback\n옵션(#285), 런처 취소 확인 대화상자를 포함하는 릴리스.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): 1.20.5",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T10:18:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e00e3f5c828ee824c22cb5bcdc99d5bd9a2a88cc",
          "body": "다운로드/작업이 진행 중일 때 닫기 버튼과 표준 닫기(제목표시줄 X / Alt+F4 /\n시스템 메뉴) 모두, 취소 여부를 묻는 확인 대화상자(MessageBox, 기본 포커스\n'아니오')를 거치게 한다. '예'일 때만 닫고, 오류/취소안내/유휴 상태에선 바로 닫는다.\n\n- IDC_CLOSE(버튼)와 WM_CLOSE(표준 닫기)를 공통 TryClose로 라우팅.\n- 진행 여부는 s_workerRunning으로 판단. 취소 = 창 닫기 = 프로세스 종료.\n- Loc: ConfirmCancelTitle/Message(ko/en). Interop: MessageBoxW + MB 상수.\n\n실측: 진행 중 close→인터셉트(프로세스 유지), 유휴/오류 close→직접 종료.\n빌드/AOT 게시 경고 0(4.94MB).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(bootstrapper): 다운로드 중 닫기 시 취소 확인 대화상자",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T09:02:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4e332c3a3a9142130acd7ec1339f3155d9d78b55",
          "body": null,
          "is_bot": false,
          "headline": "docs: README.md Markdown Linting Warning 수정",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T08:23:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "22804d0a0152ca1d06f64e03000dacc405c776ab",
          "body": "기존 하드코딩된 공용 DNS(8.8.8.8/1.1.1.1) 강제를, 사내/관리형 네트워크의\n정상 DNS를 깨지 않도록 개선한다.\n\n- SandboxBootstrap(모드 1): 이름 해석을 먼저 프로브(github.com/microsoft.com,\n  3s 타임아웃)하고 실패할 때만 공용 DNS로 폴백. 정상 DNS(사내 내부 리졸버 등)는\n  덮어쓰지 않음.\n- 옵션: PreferenceSettings.EnableSandboxPublicDnsFallback(기본 true) →\n  SporkAnswers → 게스트. false면 어\n[…]\nwsb: Resolve-DnsName 프로브 후 실패 시에만 공용 DNS 설정(인라인).\n- 문서(SPEC §0.5 / README) \"검토 중\" → \"구현됨\"으로 갱신.\n\n빌드 클린, 테스트 40/40 통과.\n\nCloses #285\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(dns): 공용 DNS를 probe-then-fallback + 옵션으로 (#285)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T08:19:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "bc404230df0625f6aabbdab843ba8c185ab2ab00",
          "body": "- no-install-spork.wsb: 간소화 인라인 기본형으로 확정 — 고정 URL로 런처를 직접\n  받아 실행(호스팅 ps1/플레이스홀더 없음, 일반 런처). DNS 선보정은\n  Set-DnsClientServerAddress 인라인.\n- spork-bootstrap.ps1: 완전 파라미터화형(핀/오프라인/MCP) 참조로 격하(헤더 명시).\n- README: '무설치(Express) 실행'을 정식 기능으로 승격(사용 방법/특징).\n- 릴리스 자산: no-install-spork.wsb 를 릴리스에 게시(build.yml/build.cs) +\n  릴리스 노트에 진입점(고정 URL) 추가.\n- 설계 문서 §11/§13/§14 갱신(§14-6 ps1 shim은 간소화가 대체).\n\n남은 릴리스 관문(버전 범프 + 태그 → 서명 → 게시)은 수동.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(no-install): 무설치 런처 정식 데뷔 (간소화 .wsb + README 승격 + 릴리스 자산)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T07:46:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "ab36f18cddb3186b4ad5bb5d9313aef82ca9fced",
          "body": "파라미터화 .wsb의 DNS 선보정(8.8.8.8/1.1.1.1 강제)이 사내/관리형 네트워크에서\n차단되거나 split-horizon 환경에선 오히려 이름 해석을 깨뜨릴 수 있음을 §0.5/§4.1에\n명시. 코드 측 DNS 강제(SandboxBootstrap 등) 옵션화는 이슈 #285로 분리(지금 구현 아님).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(wsb-spec): 사내 DNS 정책 주의 추가 + 공용 DNS 옵션화 이슈 참조 (#285)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T07:46:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "81790def0f61aa516e6ae621eb2b1b1ddc172dba",
          "body": "- README: '무설치(Express) 실행 (개발 중)' 섹션 추가 — 런처(SporkBootstrap)와\n  무설치 코어 개념 안내 + 설계 문서 링크. 권장 경로는 설치 + 샌드박스로 유지.\n- PARAMETERIZED_WSB_SPEC: 런처의 고정 URL + 자체 해석을 반영한 '§0.5 간소화된\n  기본형' 추가. 플레이스홀더 4→1(__SPORK_SITE_IDS__만, 선택), 호스팅 ps1 제거,\n  다운로드 URL/체크섬은 런처가 자체 해석, DNS 선보정은 Set-DnsClientServerAddress\n  로 LogonCommand 인라인. §3~§4 완전 파라미터화형은 핀/오프라인/MCP 용으로 보존.\n  §3.1 깨진 링크(../) 정리, §3에 완전형/간소형 구분 참고 추가.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: README 무설치 언급 추가 + 파라미터화 .wsb 스펙 간소화 첨삭",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T07:46:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "47a77edb30dc30127db149b78f9e21f777d2e26c",
          "body": "PR #284 Copilot 리뷰 5건 반영:\n- ExtractZip: --dest 재귀 삭제 가드. 비어있거나 이전 Spork 추출본(Spork.exe 존재)일\n  때만 삭제하고, 그 외 비어있지 않은 임의 폴더는 삭제 거부(데이터 손실 방지).\n- Taskbar.Init: CoCreateInstance 성공 후 예외 시에도 원본 COM 포인터를 finally 에서\n  Release(COM 참조 누수 방지).\n- WM_DESTROY: 종료 시 마지막 HFONT(s_font) + s_classNamePtr(HGlobal) 해제.\n-\n[…]\n.\n- CreateChild: CreateWindowExW 실패(0) 시 로그(WndProc 내 throw 는 AOT 위험이라 지양,\n  Win32 는 NULL hwnd 무해).\n\n빌드/NativeAOT 게시 경고 0(4.93MB).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(bootstrapper): Copilot 코드 리뷰 반영 (안전성/누수/클램프)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T07:46:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "18fec3f5581ceac273af24fad26076a7bb9c8f7e",
          "body": "런처가 무인자로 항상 최신 식탁보를 받도록 고정 URL 을 baked default 로 추가하고,\n릴리스 파이프라인에 런처와 버전프리 별칭 자산을 편입한다.\n\n- 런처 다운로드 우선순위: (1)인자(--zip-url-template) → (2)고정 URL(GitHub\n  latest/download 의 버전프리 별칭 Spork_{arch}_Portable.zip) → (3)GitHub API 폴백.\n  고정 URL 404 시 자동 폴백(실측 확인).\n- build.cs/build.yml: 버전프리 별칭 게시(Spork_<arch>_\n[…]\n1 이 draft 에서 일괄 서명.\n- 릴리스 노트에 런처 고정 URL 링크 추가.\n- 문서: 자산명 공개 계약 + 고정 URL 규약 갱신(EXPRESS_BOOTSTRAPPER_DESIGN,\n  PORTABLE_MODE2_TODO).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(bootstrapper): 고정 URL(latest/download 버전프리 별칭) + 배포 CI/CD 배선",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T07:46:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8179e4f496bb5b6150086620f5a0b3cd2703b1d9",
          "body": "Win32/GDI + NativeAOT 단일 exe(약 5MB)로 포터블 식탁보(Spork) zip 을 진행률과\n함께 받아 SHA256 검증 → 해제 → 실행한다. 큰 포터블 zip(60~90MB)을 조용히 받던\n무반응 구간을 없앤다.\n\n- UI: 순수 Win32/GDI(손수 작성 [LibraryImport], 외부 패키지 0). WPF/WinForms 는\n  내장 COM 으로 NativeAOT 불가라 제외.\n- 최신 버전: 인자(--zip-url-template) 우선, 없으면 GitHub Releases 폴백.\n- 다국어 리소스\n[…]\nrList3, 소스 생성 COM).\n- 솔루션/build.cs 편입, 자산명 SporkBootstrap_<ver>_<config>_<arch>.exe.\n- 설계/계약: docs/EXPRESS_BOOTSTRAPPER_DESIGN.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(bootstrapper): 무설치 레인용 소형 GUI 다운로더(Spork.Bootstrapper) 추가",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-05T07:46:36Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3b632549d8d7bc5de9f5fdab808deb2c5eb7344e",
          "body": "- em-dash(—) 전부 제거: '라벨 — 설명'·헤딩은 콜론(:)으로, 이중 콜론이나\n  삽입구가 되는 곳은 마침표·쉼표·괄호로 문맥에 맞게 교정.\n- 열거용 가운뎃점(·)은 쉼표(,)로 대체.\n- 대상: PARAMETERIZED_WSB_SPEC / PORTABLE_MODE2_TODO / UI_OVERHAUL_TODO / DEVELOPMENT.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: 한국어 문서 문장부호 정리 (em-dash 제거, 가운뎃점 대체)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T13:07:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "812a7ad8dd80082362c26eb3b3df07252bec4b12",
          "body": "- PARAMETERIZED_WSB_SPEC.md 신규(확정): 빠른 실행 웹앱·MCP 서버·macOS(macSandbox)\n  세 소비자가 공유하는 파라미터화된 .wsb+부트스트랩 정규 계약. 설계 B(모든 파라미터를\n  .wsb에, 부트스트랩 정적)·{arch} 토큰 URL·사이트 위치 인자·체크섬 맵으로 확정.\n  macSandbox 지원 매트릭스 근거로 동일 .wsb 하나가 WSB·macSandbox 양쪽에서 실행됨을 명문화.\n- PORTABLE_MODE2_TODO: 스캐너 일반화(92daca3)/콜드부트 준비성 완료 반영,\n[…]\n영.\n- UNIFIED_BINARY_TODO 삭제(단일 바이너리 마이그레이션 출시 완료), 잔여 참조\n  (DEVELOPMENT.md·PORTABLE_MODE2) 정리 → 깨진 링크 0.\n- 마크다운 테이블 스타일(MD060) 정리.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: Express 모드 파라미터화 .wsb 스펙 확정 + TODO 문서 상태 정리",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T12:49:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "03e470d53a2cdcce2c27b25bbabea410d612b6fc",
          "body": "Directory.Build.Props Patch 3 -> 4. 태그 v1.20.4 와 일치.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): 1.20.4 로 버전 범프",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T11:37:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a505a87306e42972b771370e3b27cd2f590078b8",
          "body": "…th(Tier 1)\n\n프라이버시 우선(보안·뱅킹 도구) 원칙 하에, 새 클라이언트 텔레메트리를 늘리기보다\n이미 있는 신호를 보강한다. 방문 사이트·뱅킹·인증서 등 PII 는 일절 수집하지 않는다.\n\n- Tier 0: 우리 엔드포인트(카탈로그) 요청에만 X-TableCloth-Version / X-TableCloth-Client\n  (host|spork; arch) 헤더를 싣는다. 서버 액세스 로그만으로 활성 실행 근사치와 버전\n  채택률을 얻는다. 제3자 다운로드용 브라우저 위장 UA 는 그대로 둔다(차단 회피 목적).\n  cli\n[…]\nogCollection)에 게이트되어 프라이버시 동의를 상속한다. Environment 로\n  host/sandbox 세션을 구분.\n\n빌드 0/0, 호스트 기동 회귀 없음. 실제 신호는 배포 후 서버 로그/Sentry 에서 관측된다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(analytics): 사용률 측정 — 카탈로그 요청 식별 헤더(Tier 0) + Sentry Release Heal…",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T11:32:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f42d512143432a3ff93d2e005bdffd523bd4bb89",
          "body": "병렬 코드 리뷰에서 나온 MINOR 3건을 정리한다(블로커/메이저는 없었음).\n\n- Edge 설치(#184): 다운로드를 ResponseHeadersRead 스트리밍 + Content-Length 기준\n  실제 진행률 보고로 변경(기존엔 전체 버퍼링 + 진행률 미보고로 진행 바가 0에 멈춤).\n  다운로드 실패/취소 시 반쯤 받은 임시 MSI 를 정리하고 다시 던지도록 보강.\n- 유휴 자동 로그아웃(#197): 경고 창 닫기에 2초 히스테리시스를 두어 임계값 경계에서\n  유휴가 진동할 때 창이 매 tick 생성/닫힘을 반복하지 않게\n[…]\n 공지(#273): workflow_dispatch 로 프리릴리스 태그가 들어오면 조용히 건너뛰도록\n  isPrerelease 가드 추가(헤더 주석의 '비-prerelease' 의도와 일치).\n\n빌드 0/0, 단위 테스트 40 통과.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: 릴리스 전 코드 리뷰 후속 수정 (#184, #197, #273)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T08:55:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a398d5f8252aadae9dfe4d715190deb5ae5fd5b5",
          "body": "새 안내 창의 'ASTx 설정 열기'에서 StSess.exe 를 Process.Start(UseShellExecute=true)로\n직접 실행하도록 바꾼 것이 안랩 보안 프로세스에 의해 접근 거부(access denied)되었다.\n/config 스위치는 이미 넘기고 있었고 문제는 실행 방식이었다.\n\n기존에 동작하던 방식(cmd /c start \"\" \"StSess.exe\" \"/config\", Helpers.CreateRunProcess,\nUseShellExecute=false)으로 되돌린다. 샌드박스에서 정상 열림 확인.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(spork): ASTx 설정 열기 실행 실패(access denied) 수정 (#275)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T07:16:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6dd43ee7e1cc9def7efb0e95f4d31e70448c4153",
          "body": "인터넷 뱅킹 사이트에서 AhnLab Safe Transaction(ASTx)의 \"원격 접속 차단\"을\n사이트 접속 전에 해제해야 Windows Sandbox(RDP)가 종료되지 않는데, 기존 안내가\n단순 OK 메시지 2개라 이 지침을 놓치는 사용자가 많았다. 안내를 전용 창으로 강화한다.\n\n- 신규 AhnLabSafeTxGuideWindow: (A) 해제 완료를 체크해야 '계속'이 활성화되는\n  확인 게이트, (B) 어떤 항목을 체크 해제해야 하는지 보여주는 시각 가이드,\n  (C) 단계별 설명 + 'ASTx 설정 열기' 버튼을 담은\n[…]\n(ko/en) 추가.\n\n주의: 설치 시점에 RDP가 죽는 일부 기관(예: 한투 마스터 빌드) 케이스는 이 창에\n도달하기 전이라 이 안내로도 못 살린다(알려진 제약). 설치는 되지만 해제를 놓쳐\n끊기는 다수에게 직접적으로 도움이 된다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): ASTx \"원격 접속 차단\" 해제 안내 강화 — 전용 창 (#275)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T06:47:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d998c760e84d6e3716ea2b4633bbac9dca2d97d5",
          "body": "새 릴리스(release: released, 비-draft·비-prerelease)가 게시되면 Discord 웹훅으로\n릴리스 공지를 임베드로 올린다. winget_publish.yml 과 동일한 트리거 방식이며,\n수동 재게시를 위해 workflow_dispatch(release_tag)도 지원한다.\n\n- 서드파티 액션 없이 curl+jq 로 구성. 릴리스 노트 본문은 jq --arg 로 안전하게\n  이스케이프하고 Discord 임베드 상한(4096)보다 넉넉히 아래(1600자)로 자른다.\n- 릴리스 데이터는 gh release vi\n[…]\necret DISCORD_WEBHOOK_URL 로만 참조(로그 마스킹).\n\n이슈/PR 알림(Discord 네이티브 GitHub 연동)과 카탈로그 리포 연동, 공지 채널\ncrosspost(게시)는 이슈 #273 의 후속 범위로 남긴다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(discord): 정식 릴리스 게시 시 Discord 공지 자동 게시 (#273)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T05:16:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6c3a24b59d9f223e666b0fb69edc1e85956d4ae9",
          "body": "일반 사용자용 매뉴얼을 GitHub Pages 대신 앱과 함께 배포되는 오프라인 HTML\n도움말로 추가한다. 실행 파일 옆 Help\\manual.ko.html 로 배포되며(Velopack은\npublish 폴더 전체를 담으므로 자동 포함), 빠른 시작 화면 하단과 프로그램 정보\n창의 '사용 설명서' 링크로 기본 브라우저에서 연다.\n\n- src/TableCloth/Help/manual.ko.html: 자체 완결형(인라인 CSS, 오프라인) 한국어\n  매뉴얼. 소개/준비물/빠른 시작/샌드박스 사용/옵션/미리 보기/FAQ/보안 안내 수록.\n[…]\nmanual.<culture>.html 을\n  우선 반환하고 없으면 ko 폴백. 영어판은 파일만 추가하면 자동 선택된다.\n- QuickStart/About 뷰모델에 OpenUserManual 명령 + UI 링크/버튼, 리소스 문자열.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(help): 앱과 함께 배포되는 HTML 사용 설명서 추가 (#40)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T04:32:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "daad39cb499349a8467829866dfd3b5ae27cd138",
          "body": "자리를 비운 사이 인증된 뱅킹 세션이 샌드박스에 열려 있는 위험을 줄이기 위해,\n일정 시간 입력이 없으면 샌드박스 세션을 자동 종료하는 미리 보기 기능을 추가한다.\n기본값은 꺼짐(opt-in)이며 옵션 창의 '미리 보기' 탭에서 켠다.\n\n구조(창을 닫아도 유지되도록 설계):\n- 유휴 모니터를 Spork 런처 프로세스가 아니라 별도의 idle-guard 프로세스로 분리.\n  StartupScript가 기능이 켜진 경우에만 `TableCloth.exe idle-guard`(신규 verb)를\n  Spork 와 독립적으로 기동한다. 사용자\n[…]\n료 트리거까지 확인. 다만 게스트 shutdown/logoff 는 세션은\n종료(보안 목적 달성)하나 WSB '창' 자체는 닫지 못하는 한계가 있어, 미리 보기\n설명과 이슈에 명시한다. 창까지 깔끔히 닫는 호스트 측 종료는 후속 과제.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): 유휴 시 자동 로그아웃 (미리 보기) — 별도 가드 프로세스 (#197)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-03T04:21:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b6a4bb17001b2e0ac10610d0920a2994dc6fe498",
          "body": "InstallEveryonesPrinter / InstallAdobeReader / InstallHancomOfficeViewer\n/ InstallRaiDrive 플래그는 예전 '보조 프로그램 자동 설치' 설계의 잔재로,\n호스트에서 조립·전달되고 Spork가 파싱까지 하지만 실제 설치로 이어지는\n소비 지점이 전혀 없다(#267에서 자동 설치 설계 자체를 제거하고 Companions\n안내 방식으로 일원화). DetailPage 에는 토글해도 아무 일도 일어나지 않는\n체크박스로 남아 오히려 사용자를 오해시켰다.\n\n설정 모델·양쪽 커맨드\n[…]\nitch/Help)·테스트에서 4종 플래그를 전부 제거한다. 프린터\n'리디렉션'(EnablePrinters/UsePrinterRedirection, 호스트 프린터 공유)과\n마이크/웹캠 리디렉션은 별개의 살아있는 기능이라 그대로 둔다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor: 동작하지 않는 보조 프로그램 자동 설치 플래그 4종 제거 (#242)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T14:34:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a8aefd0a9f5a8000b77c1cc0b7f8856eea182d33",
          "body": "'프린터 연결'을 켜면 샌드박스 안에서 '모두의 프린터' 같은 프린터\n소프트웨어가 준비된다고 오해하기 쉬운 문제(이슈 #242 파트 2)를 완화한다.\n장치 공유 탭의 프린터 체크박스 아래에, 이 옵션은 호스트 PC 프린터를\n샌드박스와 공유할 뿐 가상 프린터 앱 설치와는 다르며, 그런 소프트웨어는\n샌드박스 안에서 직접 설치해야 하고 설치 전 최신 Microsoft Visual C++\n재배포판이 필요할 수 있음을 항상 보이는 설명으로 안내한다\n(GPU 가속 설명과 동일한 체크박스-하단 설명 패턴). 파트 1(VC++ 의존성)의\n안내도 이 문구에 함께 녹였다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(options): 프린터 공유 옵션에 '가상 프린터 앱과 다름' 안내 추가 (#242)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T14:18:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "de9f7a55ac532e578f092b8a3f763a474bb2dd61",
          "body": "자동 스텝(EnsureMicrosoftEdgeStep)은 StepsPlayer 가 모든 스텝의\nLoadContent(다운로드)를 Evaluate 와 무관하게 선행 실행하는 구조라,\nEdge 가 이미 있는 정상 샌드박스에서도 대용량 Edge MSI 를 늘 내려받는\n문제가 있었다. 스텝으로 두는 대신 사용자가 필요할 때 실행하는 수동\n명령으로 분리한다.\n\n- EnsureMicrosoftEdgeStep 제거(자동 스텝 + StepsComposer 삽입 + DI 등록).\n- 다운로드/설치/탐지 로직을 IMicrosoftEdgeInstall\n[…]\n 크래시 방어 가드는 유지하고, 안내 문구를\n  새 수동 버튼으로 유도하도록 갱신.\n- 리소스: 불필요해진 Install_EnsureMicrosoftEdge 제거,\n  Sandbox_EdgeInstall_* 문자열(ko/en) 추가.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(spork): Edge 복구를 자동 스텝에서 수동 설치 명령으로 전환 (#184)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T13:44:48Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3eb277cef03a4ed07f9cdd0f9697b25dbeae30e4",
          "body": "- SandboxBuilder.DetectHostHighContrastScheme 는 고대비 꺼짐/실패 시\n  null 을 반환하므로 반환 타입을 string? 로 바로잡아 CS8603 제거\n  (TableCloth.App 은 Nullable enable).\n- TableCloth.Core 는 의도적으로 nullable-oblivious 이므로 여기의\n  string? 주석 3곳(DataDirectoryHostPath / SandboxFolder /\n  HostDotnetRootPath)을 string 으로 되돌려 CS8632 제거. null 의미는\n  기존 XML 주석에 그대로 문서화돼 있어 동작 변화는 없다.\n\n빌드 경고 11개 -> 0개. 순수 정리로 기능 변화 없음.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix: 빌드 경고 정리 (CS8603 null 반환 / CS8632 nullable 주석)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T07:02:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5fa7ccfc835540d616f8763843090596a927ea4f",
          "body": "드물게 Windows Sandbox 기본 이미지에 Microsoft Edge(msedge.exe)가 없는\n경우 사이트 열기 단계에서 기본 브라우저를 찾지 못해 Process.Start 가\n예외를 던지며 Spork 가 죽던 문제를 해결한다.\n\n- EnsureMicrosoftEdgeStep 신규 추가: Edge 가 없을 때만(Evaluate=false 로\n  즉시 skip) Microsoft Edge Enterprise MSI 를 내려받아 무인 설치한다.\n  x64 는 안정 fwlink, 그 외 아키텍처는 Edge for Busines\n[…]\n 전에 Edge 존재를 보장한다.\n- StepsPlayer: 사이트 열기 루프를 try-catch 로 감싸 브라우저 부재 시에도\n  크래시 대신 안내만 하고 계속 진행하도록 방어한다.\n- 안내/단계명 리소스 문자열(ko/en) 추가.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): 샌드박스에 Edge 부재 시 자동 복구 + 열기 실패 방어 (#184)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T06:40:42Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "12eb57469e2c503d446a81ed04ad210c8dab19ae",
          "body": "직전 수정은 TableCloth_ 접두사만 걸렀는데, 방어를 한 단계 더 높여 제출 대상 버전까지\n함께 검증한다(TableCloth_<version>.*_<arch>.exe). 이로써\n- 같은 릴리스의 Spork_* 오선택(#395443, #396257)\n- 릴리스에 어쩌다 남은 다른 버전의 TableCloth_* 오선택\n을 원천 차단하고, 못 찾으면 제출 전에 명확히 실패한다(깨진 PR 방지).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "harden(winget): 설치 관리자 선택을 버전까지 한정 (TableCloth_<version>.)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T06:13:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7a0ad87c76be50480414bc30e26512e411d538a7",
          "body": "FindInstaller 가 아키텍처만 맞으면 첫 .exe 를 골라, 같은 릴리스의 Spork_* 설치 관리자가\n알파벳순으로 TableCloth_* 보다 앞서면 Spork 를 선택했다. 그 결과 winget 매니페스트\n(TableClothProject.TableCloth)가 TableCloth 대신 Spork 를 가리켜 설치가 깨졌다\n(PR microsoft/winget-pkgs#395443, #396257). TableCloth_ 접두사 필터를 추가해 바로잡는다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(winget): 설치 관리자 선택 시 TableCloth_ 접두사로 한정 (Spork 오선택 방지)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T06:02:14Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "78fd1823d69e26ee845f286b500b9b313b448fbb",
          "body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v1.20.3",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T05:37:48Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e889b04b15e4e00768d0e613f13df4433a79c6de",
          "body": "태그 릴리스의 Release 게시 직후, vpk pack 전에 publish/publish-spork 의 .pdb 를 symbols\\ 로\n빼내(설치본 nupkg 에 심볼 미포함) 아키텍처별 TableCloth_<버전>_<arch>_symbols.zip 으로 묶어\n릴리스 자산으로 올린다(SBOM 과 동일 패턴, releases/* 업로드 경로 재사용).\n\n릴리스를 만든 바로 그 게시 출력에서 수집하므로 PDB 서명이 바이너리와 정확히 일치한다.\n개발자 크래시 덤프 분석용이며 최종 사용자는 받지 않는다(릴리스 노트에 명시).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci: 릴리스에 매칭 PDB(symbols.zip) 자산 추가 + 설치본에서 PDB 제외",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T05:37:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "05d9086d27c2a20d2697ea5aeefc29e23ff25e83",
          "body": "이전 방식(Control Panel\\Desktop 만 기록 + 단발/다단계 보정)은 로그온 시 테마가 기본 배경을\n늦게 다시 적용하면 되돌아갔다(단발이면 기본 고정, 다단계면 번쩍임).\n\n이제 시작 배치가 '데스크톱 배경 강제' 사용자 정책\n(HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Wallpaper)까지 함께 심는다.\n이 정책이 있으면 셸이 이 이미지를 적용하고 테마가 덮어써도 정책이 우선하므로 기본 배경으로\n되돌아가지 않는다. 스타일(채우기)은 Control Panel\\Desktop\\WallpaperStyle 로 지정.\n\n이에 따라 SandboxBootstrap 의 배경 재적용/워치독 코드와 관련 P/Invoke를 모두 제거했다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(sandbox): 다크 배경을 강제 정책으로 잠가 기본 배경 되돌림 방지 (#246)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T04:02:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "43be1719e6160ec3a76246ccaec2ba6b1c3ef132",
          "body": "여러 단계 재적용(0/2/5/10초)이 매번 화면을 번쩍이게 하던 문제를 제거한다.\n\n- 최초 설정 분기: 시작 배치(StartupScript.cmd)가 셸 초기화 전에 HKCU\\Control Panel\\Desktop\n  (Wallpaper/WallpaperStyle=채우기/TileWallpaper)에 다크 배경 이미지를 기록한다. 셸이 부팅 시\n  이 값을 읽어 처음부터 해당 이미지를 그리므로 이상적으로는 깜빡임이 없다.\n- 단일 보정: SandboxBootstrap은 셸(Progman)이 뜬 뒤 현재 배경이 우리 이미지가 아닐 때만\n  딱 한 번 SPI_SETDESKWALLPAPER로 보정한다(이미 우리 이미지면 재적용하지 않아 깜빡이지 않음).\n  기존 다단계 재적용/중복 레지스트리 쓰기는 제거.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(sandbox): 다크 배경 깜빡임 제거 — 최초 설정 분기 + 단일 보정 (#246)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-07-01T02:27:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "a1acc9d9f3d48d319d24c53ba116ece87a54810f",
          "body": "셸(explorer) 부팅 초기화가 기본 배경을 한 번 덮어쓰는 타이밍 경합 때문에 한 번만\nSPI_SETDESKWALLPAPER 하면 곧 기본 이미지로 되돌아갔다. (1) HKCU\\Control Panel\\Desktop에\nWallpaper/WallpaperStyle(채우기)/TileWallpaper를 먼저 기록하고, (2) 부팅 안정화까지\n0/2/5/10초에 걸쳐 재적용해 우리 이미지가 마지막에 적용되도록 한다.\n\n독립 Spork 제외: 배경 변경은 Spork.Sandbox(SandboxBootstrap)에만 있고, 단독 Spor\n[…]\n\n이 어셈블리를 참조하지 않아 NoopSandboxBootstrap을 쓰므로 동작이 포함되지 않는다(추가 변경 불필요).\n또한 IsRunningInSandbox(WDAGUtilityAccount) 가드로 호스트에서는 실행되지 않는다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(sandbox): 다크 배경이 기본 이미지로 되돌아가는 문제 수정 (#246)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-30T12:04:01Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4688b1ce3121cf0c03279ea6f395e3bf8cea1dd5",
          "body": "고대비(High Contrast)\n- 호스트의 고대비 구성표를 SandboxBuilder가 SPI_GETHIGHCONTRAST로 읽어\n  SporkAnswers.HostHighContrastScheme로 전달한다(꺼져 있으면 null).\n- 샌드박스 부팅 시 SandboxBootstrap이 같은 구성표 이름으로 SPI_SETHIGHCONTRAST를 적용한다.\n  호스트와 동일 OS·로캘이라 구성표 이름이 호환된다. 베스트에포트(프로그래밍 방식 적용은\n  환경에 따라 완전하지 않을 수 있음).\n\n다크 모드 배경 이미지\n- 다크 모드로\n[…]\n- 시작 시점 적용만 가능(RDP 한계로 세션 중 호스트 테마/고대비 전이는 미반영).\n- 고대비의 프로그래밍 방식 적용은 일부 환경에서 부분적으로만 반영될 수 있음.\n- 배경 이미지는 다크 모드 시작에만 적용(라이트는 기본 유지).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(sandbox): 고대비 전파 + 다크 모드 시작 배경 이미지 (#246)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-30T11:57:03Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e7b48da5eaca3b67718c59087a43d2f539ebb855",
          "body": "구현\n- 호스트의 라이트/다크 선호(HKCU\\...\\Themes\\Personalize\\AppsUseLightTheme)를\n  SandboxBuilder가 읽어 SporkAnswers.HostUsesLightTheme(bool?)로 전달한다.\n- 샌드박스 부팅 시 SandboxBootstrap이 이 값으로 게스트의 AppsUseLightTheme +\n  SystemUsesLightTheme를 설정하고, 설정 앱과 동일하게 WM_SETTINGCHANGE(\"ImmersiveColorSet\")를\n  브로드캐스트해 이미 떠 있는 셸/앱을 갱\n[…]\n리.\n- 호스트의 단일 신호(AppsUseLightTheme)를 게스트의 앱/시스템 테마에 함께 적용(분리 미지원).\n- 브로드캐스트로 대부분 갱신되나, 이미 떠 있는 일부 셸 표면은 상호작용 전까지 완전 리페인트가 지연될 수 있음.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(sandbox): 호스트 라이트/다크 테마를 샌드박스 시작 시점에 반영 (#246)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-30T11:41:17Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b3d5feedc2ae06879aa2aabcf52b18a7bc52388d",
          "body": "- About 창에 기여자 섹션 신설: contributors.json 소비, 아바타+이름, 익명 기여자 집계 표시\n- 후원자 섹션에 익명 후원자 집계 칩 추가 (SponsorsDocument.AnonymousCount)\n- About 창에 Discord 링크 버튼 추가 (CommonStrings.DiscordUrl)\n- TableCloth.App + Spork.App 양쪽 적용, ContributorInfo 모델 + 관련 리소스(한/영) 추가\n- 데이터는 yourtablecloth.app/{contributors,sponsors}.json 소비 (생성기는 yourtablecloth.github.io/deploy.yml)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(about): 기여자 명단 + 익명 후원자 집계 + Discord 링크 (#195)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-30T11:20:42Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "c98e2fdf24da7e26c36ce29e709db5e06c7f024c",
          "body": "임시 작업 폴더(비-git)에서 gh release download/upload를 호출하면 repo 컨텍스트가\n없어 'no git remotes found'로 실패한다. -Repo 매개변수(기본값 yourtablecloth/TableCloth)를\n추가하고 두 gh 호출에 --repo 를 명시해 어느 디렉터리에서 실행해도 동작하게 한다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(tools): sign-release.ps1에 --repo 명시로 'no git remotes' 실패 방지",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-30T10:40:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2d3ea08dbae5ca46ef3726dc557e73fa30bc19aa",
          "body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(release): v1.20.2",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-30T10:21:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "44e65cae34f33df4a9902fe94dc64ce980486229",
          "body": "- 옵션 창에 '데이터 디렉터리' 탭 신설: 현재 경로 표시 + 폴더 선택/기본값으로/열기,\n  PreferenceSettings.DataDirectoryHostPath 저장 (Phase 1.5에서 제거됐던 UX 재도입)\n- 비로컬(네트워크/클라우드/이동식 드라이브·UNC) 경로 경고 노출, 샌드박스 시작 직전\n  마운트 가능성을 검사해 차단하고 데이터 디렉터리 탭으로 안내 — 문서 폴더가 네트워크\n  드라이브로 강제 지정된 환경 대응\n- 시작 시 폴더 생성을 거부하거나 생성에 실패하면 데이터 디렉터리 탭으로 딥링크,\n  생성 실패\n[…]\n 여부 확인\n- 마운트 가능성 판정을 ISharedLocations.IsMountableDataDirectory로 중앙화\n- 기본 경로(Documents\\TableCloth\\Data)는 유지 (기존 사용자 데이터 마이그레이션 불필요)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(tablecloth): 데이터 디렉터리 사용자 지정 + 비로컬 경로 차단 (#282)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-28T06:13:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "c8f501cd0eba062b22b02c1d0735f4197d645089",
          "body": "단독/무설치 Spork 의 카탈로그가 아이콘과 함께 즉시 뜨고, 사용자가 직접 갱신할\n수 있게 한다.\n\n- ServiceLogoConverter: 로컬 images\\{id}.png 우선(모드 1·오프라인 동봉),\n  없으면 카탈로그 서버의 {ImageUrlPrefix}/{Category}/{Id}.png 에서 비동기\n  로드(UI 비차단). 바인딩을 ID 문자열 대신 서비스 객체로 바꿔 Category 확보,\n  ID별 캐시 + 실패 시 캐시 제거로 새로고침 재시도\n- MainWindowViewModel.RefreshCatalog: 카탈로그를 네트워크에서 다시 받아 UI 재구성\n- MainWindow.xaml: 카탈로그 검색행에 새로고침 버튼 추가\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): 카탈로그 사이트 아이콘 로드 + 동적 새로고침",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-25T15:16:35Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "83f17046563b7e143e62b8c07ae2e121dd732f60",
          "body": "단독/무설치 Spork 도입에 맞춰 사용자 문구를 정리한다(en/ko).\n\n- 미사용 '포카락' 브랜딩 문자열 제거: Spork_AppTitle, Spork_TitleText_*,\n  Spork_DryRunInstructionMessage, Spork_Shortcut*, Error_Already_Spork_Running\n  (브랜드 통일 후 BrandStrings 가 더 이상 참조하지 않음)\n- 카탈로그 새로고침 버튼 문자열 추가: SporkCatalog_RefreshButton\n- Spork 가 샌드박스 밖(사용자 VM 등)에서도\n[…]\n문구의 '샌드박스'를\n  '환경'으로 일반화: SporkCatalog_Certificates_Description/Empty,\n  TableCloth_ShortcutDescription (호스트 식탁보의 샌드박스 문구는 그대로 유지)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore(resources): Spork 리소스 문자열 정비",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-25T15:16:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3064dc191fb2b6e12fb7d1ef4494478c0e863457",
          "body": "단일 바이너리 통합 이후 단독 Spork 도 식탁보로 보이도록 브랜드를 일원화한다.\n표시 이름/아이콘만 식탁보로 바꾸고, AssemblyName \"Spork\" 는 exe 파일명·verb\n디스패치·바로가기 인자 등 기능적 식별자로 유지한다.\n\n- BrandStrings: 표시 문자열(제목/메시지/바로가기 이름)을 entry 분기 없이 항상\n  식탁보로. ShortcutArguments 만 exe 디스패치용으로 entry 기반 유지(기능적)\n- src/Spork/App.ico: 식탁보 exe 아이콘으로 교체\n- Spork.csproj: Title/Description 을 식탁보 브랜드로 정렬\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(spork): '포카락' 브랜드 폐기, UI를 식탁보로 통일",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-25T15:15:52Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dfc432e89e6c661545cc57d3ed4d699657c554e0",
          "body": "단독/무설치 Spork 시나리오가 첫 화면부터 오프라인으로 동작하도록 산출물을\n구성하고, 배포 웹앱이 의존할 계약과 단독 테스트 진입점을 마련한다.\n\n- build.cs: Spork 포터블 산출물에 카탈로그 스냅샷 + 사이트 아이콘(Images.zip의\n  .png) 동봉, 다운로드 자산명(Spork_*_Portable.zip) 공개 계약 주석,\n  패키지/바로가기 아이콘을 식탁보와 동일하게 정렬\n- tools/no-install/: 폴더 마운트 없는 무설치 .wsb 템플릿 + 부트스트랩 스크립트\n  (다운로드 전 DNS 보정 → \n[…]\n프\n- tools/make-test-wsb.cs: publish 없이 dotnet build 출력 + 호스트 dotnet 폴더만\n  마운트해 Spork 를 단독 실행하는 .wsb 생성기(File-based App), 아이콘 동봉 포함\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(spork): 무설치·포터블 Spork 인프라 (패키징·.wsb 템플릿·테스트 도구)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-25T15:15:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "92daca3e1bcdd903a8843682ae5a2117dd0d1a47",
          "body": "단독 Spork(모드 2: 사용자 VM / 무설치 WSB)를 지원하기 위해 카탈로그 인증서\n스캐너가 WDAGUtilityAccount LocalLow 경로에 하드코딩되지 않도록 일반화한다.\n\n- IX509CertScanner.ScanSandboxNpkiCertificates → ScanLocalNpkiCertificates\n- 후보 루트 집합으로 스캔: 실제 LocalLow\\NPKI(계정명 비종속) + WSB canonical +\n  Desktop\\NPKI 마운트 + 제거식 드라이브(USB), CertHash 로 중복 제거\n- WSB 안에서는 LocalLow 가 canonical 과 동일 경로로 풀려 모드 1 비회귀\n- 모드 2 설계/인프라 계획 문서(docs/PORTABLE_MODE2_TODO.md) 추가\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): NPKI 인증서 스캐너를 환경 비종속으로 일반화",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-25T15:15:21Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e274cd05b5d9a8b6a6600a95a316fff55bcb14e5",
          "body": "UNIFIED_BINARY_TODO.md 에 Phase 9 추가(열린 Phase 8 패키징 항목 완료, Spork.slnx\n통합·제거), RELEASING.md 에 두 앱 산출물 + 연속 릴리스 시 Releases 폴더 정리 주의 반영.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(spork): Spork 단독 패키징 + 솔루션 통합 기록 (Phase 9)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-23T12:34:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b4563b0e164be0edc6f94d0f4d8896c4170b45c8",
          "body": "build.cs / build.yml 의 빌드 루프에 Spork publish(단일 파일 self-contained) +\nvpk pack + rename 단계를 추가해, 단독 배포/재사용 아티팩트인 Spork.exe 를\nTableCloth 와 같은 릴리스에 함께 게시한다.\n\n- 채널을 spork-<arch> 로 두어 TableCloth(채널 <arch>)와 메타데이터\n  (releases.<channel>.json/RELEASES-<channel>/assets.<channel>.json) 이름 충돌 회피\n  → 같은 releases\n[…]\n리스 노트 Downloads 에 Spork 항목 추가\n\n로컬 build.cmd --sign 검증: TableCloth/Spork x64+arm64 Setup.exe 4종 모두 서명 Valid,\n한 폴더에서 채널로 구분되어 충돌 없음.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(spork): Spork 를 TableCloth 와 같은 Velopack 형태로 패키징",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-23T12:34:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3b871404b12228ac41de8773cadd171673d93eb3",
          "body": "단독 배포/재사용 아티팩트인 Spork.exe(src/Spork)를 별도 Spork.slnx 대신 메인\nTableCloth.slnx 에서 함께 관리한다. 솔루션 파일은 빌드 컨테이너일 뿐이라 같은\n솔루션 안에서도 Spork.csproj 만 독립 publish/pack 할 수 있다. Velopack 패키징은\n후속 단계에서 build.cs/build.yml 에 추가한다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "refactor(solution): Spork.slnx 제거, Spork.csproj 를 TableCloth.slnx 로 통합",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-23T12:18:21Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d40410f778d55c6fa863bef5d58adff18e674feb",
          "body": "다크모드 색상 대응(InfoBanner/보조 텍스트, Spork 즐겨찾기 별·설치 상태),\n사칭·피싱 안내문, winget 자동 제출/포크 동기화, 로컬 전체 서명(build.cs --sign)\n등 v1.20.0 이후 수정 사항을 패치 릴리스로 묶는다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: 버전 1.20.1.0 으로 bump",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-23T11:49:13Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "8f0dcc39b49052fbd2e9eb2a2176c62a6a592865",
          "body": "- 즐겨찾기 별: 외곽선 Stroke=\"Black\"(다크모드 배경에서 안 보임) →\n  {DynamicResource ControlDefaultForeground}, 비활성 채움 LightGray →\n  ControlSecondaryForeground (선택 시 금색 #FFD401 유지). Spork MainWindow +\n  TableCloth CatalogPage/DetailPage 의 동일 별 컨트롤에 모두 적용.\n- StateToBrushConverter: 설치 상태 텍스트 색을 DarkGreen/DarkRed(다크 배경에서\n  대비 부족) → 라이트/다크 양쪽에서 읽히는 중간 톤(green/red/amber)으로 변경.\n\n배지(설치 표시: 초록 #2EA043 + 흰 글리프, 호버 파랑)는 의도된 강조색이라 유지.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): Spork 즐겨찾기 별·설치 상태 색상 다크모드 대응",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-23T04:10:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d7d00dcd3ee9c438d1b4e5f3cc1404ac2d8b780b",
          "body": "InfoBanner* 브러시가 App.xaml(앱 수준, 라이트 고정)에 정의돼 있어 ThemesController\n가 머지하는 테마 사전보다 우선순위가 높았고, 그 결과 다크모드에서도 배너가 밝게\n표시되는 문제가 있었다. 또 ControlSecondaryForeground 가 11곳에서 사용되지만 어디\n에도 정의돼 있지 않았고, 일부 텍스트는 Foreground=\"Gray\"/\"LightGray\" 로 하드코딩돼\n테마를 따르지 않았다.\n\n- App.xaml(TableCloth.App/Spork.App)에서 InfoBanner* 제거\n\n[…]\n정의 (다크는 어두운 슬레이트 배경 +\n  밝은 텍스트/링크)\n- 하드코딩 Gray/LightGray 텍스트(워터마크/캡션/상표 문구 등)를\n  {DynamicResource ControlSecondaryForeground} 로 교체\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(ui): InfoBanner·보조 텍스트 색상을 테마(다크모드) 대응으로 전환",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-23T03:50:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8d132f007e2fcceaeba2c1a085a7843d833fb48e",
          "body": "식탁보 사칭/피싱 악용 방지를 위해 README 상단에 CAUTION 안내를 추가.\n① 본인인증·결제·금전 절대 요구 안 함 ② 광고성 다운로드 링크 주의(정식\n배포는 GitHub Releases/winget) ③ 배포 프로그램은 전부 무료.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): 사칭·피싱 주의 안내문 추가 (#272)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-22T14:38:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d540267d20361ec8d87c7c76c352ca0eba6d7c57",
          "body": "버전 bump → 태그 push(CI 미서명 draft) → build.cmd --sign(로컬 전체 서명) →\ngh release upload --clobber → UNSIGNED 제거 후 Publish → winget 자동 PR 까지의\n릴리스 절차를 단계별로 문서화. 실제 build.yml/winget_publish.yml/build.cs 와\n대조 검증한 주의점(태그 커밋이 winget 스크립트를 포함해야 함, 머지 전 중복 PR\n위험, 3-part 버전만 검증 등) 포함.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: 릴리스 절차 런북 추가 (docs/RELEASING.md)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-22T14:19:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "997cd0f333aa99e6fd20229495a41025cae582fd",
          "body": "wingetcreate 는 PAT 소유자의 winget-pkgs 포크에 PR 브랜치를 만드는데, 포크 master\n가 upstream 보다 크게 뒤처지면(winget-pkgs 는 매우 활발) 제출이 실패한다. 실제로\n209k 커밋 뒤처진 포크 때문에 v1.20.0 첫 제출이 실패했다. 매 제출 전 GitHub\nmerge-upstream API 로 포크 master 를 fast-forward 하여 자동 제출을 견고하게 한다.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(winget): 제출 전 winget-pkgs 포크를 upstream과 동기화",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-22T14:04:37Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "356722ae0c1916ec167c46de25d1b7ca5bebeb72",
          "body": "로컬 빌드에서 SimplySign(CurrentUser\\My) 인증서로 앱 바이너리 + Update.exe +\nSetup.exe 를 vpk pack 시점에 한 번에 서명한다. --channel 로 아키텍처를 분리하고\n출력을 TableCloth_<버전>_<config>_<arch>{.exe,_Portable.zip} 규칙으로 rename 하여\n서명된 산출물을 그대로 GitHub 릴리스에 업로드할 수 있다 (winget 자산 매칭과도 호환).\n\n- --sign/-S, --sign-subject(또는 TABLECLOTH_SIGN_SUBJECT), --timestamp-url 옵션\n- 빌드 전 인증서(개인 키) 사전 검증\n- vpk 호출을 ArgumentList 기반으로 변경해 signParams 따옴표 처리 안전화\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(sign): build.cs --sign 으로 Velopack 전체 코드 서명 자동화",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-22T13:41:36Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7abab156e2a5ea1b338c9153e51d5c39d79a3246",
          "body": "정식 릴리스(released) 게시 시 microsoft/winget-pkgs 에 TableClothProject.TableCloth\n매니페스트 업데이트 PR 을 자동 제출한다. 수동 재제출용 workflow_dispatch 도 지원.\n\n- 기존 수동 winget_publish.yml 을 .NET 10 file-based app(Cadenza SDK) 호출로 교체\n- tools/winget/submit-winget.cs: 릴리스 조회 → x64/arm64 자산 선택 → wingetcreate update --submit\n- 멀티 아\n[…]\n환경 변수로 전달 (명령줄 노출 방지)\n- 멱등성: 이미 등록된 버전이면 건너뜀, 조회 불확실 시 중복 방지 위해 중단\n- tools/Directory.Packages.props: file-based app 의 루트 CPM 상속 차단\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(winget): 릴리스 시 winget-pkgs 매니페스트 PR 자동 제출 (.NET 10 + Cadenza)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-06-22T12:31:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "17cedf5105d23e1ebae70494e3bbdd3ba449fe78",
          "body": null,
          "is_bot": false,
          "headline": "chore: bump TableClothCatalog submodule (934caf9 → 37cb722)",
          "author_name": "rkttu",
          "author_login": "rkttu",
          "committed_at": "2026-06-22T11:40:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0eb92b066315bb9ce59485e8f0861930dc588c20",
          "body": "InputPasswordWindowViewModel 생성자가 TaskFactory 매개변수를 받지만\n_taskFactory 필드에 할당하지 않아 _taskFactory == null 상태로 남아 있었다.\n이후 InputPasswordWindow의 Loaded 이벤트가 InputPasswordWindowLoaded →\nNotifyViewLoadedAsync 를 호출하면 _taskFactory.StartNew(...) 에서\nNullReferenceException 이 발생하고, 인증서 선택 창 위에 거대한 stack trace\n대화 상\n[…]\n 추가하면서 본문의\n할당 라인을 함께 추가하지 않은 누락. 같은 패턴의 다른 ViewModel\n(OptionsWindowViewModel 등)은 모두 _taskFactory = taskFactory 가 들어있다.\n\nFixes #280\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(certs): pfx 가져올 때 InputPasswordWindow에서 NullReferenceException 수정",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-24T11:32:19Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "13995558791e2609f10c254bcca6570358d3b77a",
          "body": "기존에 SandboxBuilder에서 하드코딩되어 있던 vGPU=Disable을 사용자가\n명시적으로 제어할 수 있도록 단일 옵션 EnableSandboxGpuAcceleration\n(PreferenceSettings)으로 추출. 기본값은 false로 유지되며, 호환성과\n안정성 우선 정책을 명문화한다.\n\n옵션 OFF (기본):\n  - WSB: <vGPU>Disable</vGPU>     (호스트 GPU 미공유)\n  - StartupScript: HKLM\\SOFTWARE\\Policies\\Microsoft\\Edge\n            \n[…]\n/미디어 등 GPU 가속이 꼭 필요할 때만 사용자가 명시적으로 켠다.\n\n옵션 창에 새 \"호환성\" 탭을 신설해 체크박스와 보조 설명문을 노출.\nv1.20.0 draft 이전 단계라 기존 설정 마이그레이션 불필요.\n\nCloses #263\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(sandbox): GPU 가속 통합 옵션화 (기본 OFF) + vGPU 토글링",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-24T11:29:44Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ae474bf151a0c575c365375ac2fa889f986fa058",
          "body": "기존 \"샌드박스 내 바탕 화면에 바로 가기로 연결\" 표현은 실제 동작과 다름.\n호스트 폴더는 호스트와 동일한 경로가 아닌, 샌드박스 Desktop 아래에 원본\n폴더 이름 그대로 마운트(예: D:\\Work → 바탕 화면\\Work)되어 표시된다.\n사용자가 폴더 매핑을 처음 접할 때 어디로 연결되는지 즉시 알 수 있도록\n한국어/영어 양쪽 문구를 다듬고 예시를 포함한다.\n\nCloses #274\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(i18n): 폴더 매핑 설명 문구를 실제 동작에 맞춰 명확화",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-24T11:28:48Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "b306f7a933e6813d5727e4c8674ae4613f9ad2cb",
          "body": "릴리스에 첨부되는 자산이 14개에 달해 사용자가 어떤 파일을 받아야 할지\n직관적이지 않은 문제를 해결한다. 본문 상단에 Downloads 섹션을 prepend 해\nInstaller / Portable 각각 x64 · arm64 4개 링크만 직접 노출하고, 나머지\nnupkg / RELEASES / json / sbom 는 자동 업데이트 메타와 SBOM 으로\n명시한다.\n\nPortable.zip 파일명도 Setup.exe 와 동일한 규칙으로 통일:\nTableCloth_<full-version>_<configuration>_<arch>_Portable.zip\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci: 릴리스 노트에 Downloads 섹션 추가 + Portable.zip 파일명 형식 통일",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T14:37:09Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "57cc829480fe458b14102c45a7cbc6f79aa16126",
          "body": "dotnet run --file 로 실행되는 external/TableClothCatalog/src/catalogutil.cs\n가 repo root 의 Directory.Packages.props 를 walk-up 으로 발견하면서\nManagePackageVersionsCentrally=true 가 적용되고, catalogutil.cs 의\n`#:package <name>@<version>` 인라인 버전 지정과 충돌해 NU1008 → 빌드 실패 →\nImages.zip 미생성 으로 TableCloth.csproj 의 BuildCatalo\n[…]\nalk-up 경계로 두어 submodule 의\nfile-based app 이 root CPM 을 상속하지 않게 차단한다. NuGet 의 nearest-wins\n규칙상 external/ 하위 파일들은 이 비활성 props 만 사용한다.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(build): external/ 아래 file-based app 의 CPM 충돌 해결",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T11:21:47Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0034199c3f58a84cbaaecb274b0f0ec631675c8c",
          "body": "Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: 버전 1.20.0.0 으로 bump",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T11:13:27Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "aea85ffcd4ffd01b72cb91dc26bf7de4e3d0c1a9",
          "body": "CI 는 draft 릴리스만 생성하고, SimplySign Desktop 으로 로그인된\n로컬 머신에서 tools/sign-release.ps1 로 .exe 자산을 다운로드 →\nsigntool 서명 → 재업로드한 뒤, 브라우저에서 UNSIGNED 마커를\n제거하고 publish 하는 흐름을 표준화한다.\n\n추가로 vpk pack 에 --channel <arch> 를 지정해 x64/arm64 산출물\n파일명 충돌(release-assets/ 덮어쓰기)을 제거하고, Setup.exe 를\nTableCloth_<full-version>_<configuration>_<arch>.exe 형식으로\n일관되게 rename 한다.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci: draft 릴리스에 UNSIGNED 마커와 로컬 서명 워크플로 추가",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T11:13:22Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "841ae4cdf4ad062a8b297072661807d6ba4025f4",
          "body": ".wsb 로 sandbox 가 시작될 때 inner 데스크톱이 클라이언트 영역과 동기화되지 않아\n작게 렌더링되는 OS 버그(WindowsSandboxClient/WindowsSandbox)에 대한 수동 우회 방법을\nDEVELOPMENT.md 의 Known Issues 섹션에 정리.\n\n호스트 측에서 Maximize-Restore 토글을 자동 발화시키는 SandboxRenderNudger 보정\n로직을 한 차례 시도했지만 첫 페인트 타이밍/윈도우 핸들 등장 순서/UWP wrapper 유무\n등 변수가 많아 신뢰성 있게 동작하지 않아 도입하지 않은 이력을 함께 남김. 향후 재시도\n시 고려할 접근(자식 윈도우 깊이 탐색 / UIAutomation / Microsoft fix 대기)도 함께 기록.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: Windows Sandbox 첫 부팅 렌더링 축소 이슈를 Known Issue 로 기록",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T10:26:51Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "05b421003851ac651e4149de8a3bb0341647fcf8",
          "body": "EnterCatalogInstallFlowAsync 가 InstallStepsWindow.ShowDialog() 의 bool 결과로만\n사이트 오픈 여부를 결정하다 보니, false 가 \"설치 실패\" 와 \"사용자 취소\" 양쪽\n모두를 의미하는 상황에서 실패 케이스에도 사이트가 안 열리는 회귀가 있었다.\n명령줄(--select) 경로의 StepsPlayer 주석엔 이미 \"설치 성공 여부와 관계없이\n항상 웹 사이트를 열어줍니다.\" 라는 의도가 명시되어 있어 카탈로그 모달 경로만\n어긋난 상태.\n\nInstallStepsWindowViewMod\n[…]\n\n- 취소 → 자동 오픈 건너뜀 (사용자 의사 존중)\n\nCloseDialog → RaiseCloseAsync(Succeeded ?? false) 는 그대로라 DialogResult 의\n외부 의미(취소·실패 = false)는 보존된다.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(spork): 설치 실패 시에도 카탈로그 진입 후 사이트가 열리도록 수정",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T10:10:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d78b83cf5d1c43fa8d68e11a21d3c6afeb5bf0ec",
          "body": "Visual Studio 18.x 의 StronglyTypedResourceBuilder 가 자동 재생성한 부산물.\nauto-gen 헤더 코멘트가 한국어로 바뀌고 GeneratedCodeAttribute 의 버전 토큰이\n\"17.0.0.0\" → \"18.0.0.0\" 으로 갱신되었다. 기능 변경 없음.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chore: Resources.Designer.cs 자동 재생성 결과 반영 (코멘트 로컬라이즈 + 툴 버전 17→18)",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T09:49:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "aa5979e21332a01ef107ed14dc6ddc2da87e738d",
          "body": "기존 StartupScript.cmd 는 set 만 사용해 batch 프로세스 트리에서만 DOTNET_ROOT 가\n유효했다. 바탕화면 바로가기 클릭처럼 LogonCommand 흐름 밖에서 새로 띄우는 프로세스는\nDOTNET_ROOT 를 모르므로 framework-dependent dev 빌드의 재실행이 hostfxr 해석에서\n실패한다.\n\nsetx 를 함께 호출해 HKCU\\Environment 에 영구 등록 + WM_SETTINGCHANGE 브로드캐스트.\n이후 Explorer 셸이 띄우는 모든 새 프로세스가 DOTNET_ROOT 를 \n[…]\n 채워진 dev/framework-dependent 경로에만 들어가므로\nself-contained 릴리스 빌드의 StartupScript.cmd 에는 영향 없음. sandbox VHD 안\nHKCU 라 호스트 머신 환경에도 영향 없음.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(sandbox): dev 빌드에서 DOTNET_ROOT 를 사용자 단위로 영구 등록",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T09:48:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b8f2c2d17a48998c9f182af05bbdadf790b1c177",
          "body": "TryCreateSporkShortcutAsync 가 CreateShortcutOnDesktopAsync 의 arguments 파라미터를\n지정하지 않아 바로가기가 항상 인자 없이 TableCloth.exe 를 띄웠다. TableCloth.exe 는\nverb 디스패처라 spork 토큰이 없으면 호스트 런처 모드로 빠지며, sandbox 안에서는\n의미 있는 동작을 못해 \"다시 실행\" 시나리오가 깨졌다.\n\nBrandStrings 에 ShortcutArguments 속성을 신설해 entry 어셈블리에 따라 알맞은 인자를\n돌려준다:\n- Ta\n[…]\n 통과 필수)\n- Spork.exe entry      → \"\" (단독 진입점이라 인자 불필요)\n\nTryCreateSporkShortcutAsync 가 본 속성을 그대로 전달해 entry 종류와 무관하게\n바로가기가 올바르게 동작한다.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(spork): 샌드박스 바탕화면 바로가기에 spork verb 인자 추가",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T09:47:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "e5ac852c08341854b92a6d59b9baf11f82c2a076",
          "body": "…기본값 보장\n\nCI/CD 가 `dotnet publish -c Release -r win-x64 -o ...` 로 호출하면 .NET 8+ 부터는\n-r 만으로 self-contained 가 자동으로 켜지지 않는다. csproj 의 publish-conditional\nPropertyGroup 이 EnableCompressionInSingleFile=true 를 강제하는데 SelfContained 가\n켜지지 않은 상태로 단일 파일 번들을 만들면 다음 오류로 빌드가 실패한다:\n\n  \"자체 포함 애플리케이션이 게시된 경우 단일 파일 번들의\n[…]\n\n검증: dotnet publish src/TableCloth/TableCloth.csproj -c Release -r win-x64 →\n89MB single-file self-contained TableCloth.exe 정상 산출.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "build(publish): EnableCompressionInSingleFile 와 짝이 되도록 SelfContained …",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T09:24:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "54463ad3d58e6c455329a12f3d620135745d26d1",
          "body": "Spork.App 코드 베이스는 TableCloth.exe(통합 진입점) 와 Spork.exe(단독 출시)\n양쪽에서 호스팅되는데 UI 에 표기하는 브랜드(\"식탁보\" vs \"포카락\")는 entry point\n에 따라 달라야 한다. 정적 리소스 매핑만으론 분기되지 않으므로 런타임에\nAssembly.GetEntryAssembly().GetName().Name 으로 한 번 판정한 결과를 캐시하고\n각 리소스 변형 중 알맞은 쪽을 돌려주는 BrandStrings 라우터를 도입한다.\n\n- 신규 Spork.Components.BrandString\n[…]\n려 주세요.\" 로 축약\n\n결과: TableCloth.exe → sandbox UI 전반에서 \"식탁보\" 표기. Spork.exe 단독 출시\n(비-샌드박스 재단 릴리스 포함) → \"포카락\" 표기. 같은 어셈블리가 환경에 맞게\n자동 분기.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "i18n(spork): entry-aware 브랜드 라우팅 + 설치 진행 안내 문구 단순화",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T09:24:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "dc2488dc6959338c20b8316e93df4d90aaaa00d1",
          "body": "전역 \"강제 재설치\" 체크박스를 폐기하고, 이미 완전 설치된 사이트의 좌상단\n체크 배지 자체를 인터랙티브 컨트롤로 만든다. 즐겨찾기 별 토글과 같은 결의\n직접 조작 UX:\n\n- 평상시: 녹색 ● + ✓ (배지)\n- hover: 파란색 ● + ↻ (새로 고침 글리프로 morph) + 툴팁 변경\n- 클릭: \"이 사이트의 모든 패키지를 다시 설치할까요?\" 확인 다이얼로그\n  → Yes 시 해당 사이트만 forceReinstall=true 로 설치 흐름 진입\n\n모델 변경:\n- IInstallRecordStore.ForceReinstall(\n[…]\n쪽 진입점 통일)\n- 옛 MainWindow_ForceReinstall* 리소스 문자열 제거,\n  CatalogCard_ForceReinstallTooltip + Spork_ForceReinstall_Confirm 추가 (en/ko)\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): 강제 재설치 UX를 사이트별 배지 인터랙션으로 통합",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T08:51:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "510d57bba8901d67eea8d24695af22e7822684ef",
          "body": "같은 사이트를 여러 번 진입하는 워크플로에서 매 번 같은 패키지를 다시 설치하지\n않도록, 설치 완료된 항목의 fingerprint 를 캐시하고 StepsComposer 가 카탈로그\n정의와 비교해 이미 설치된 항목을 파이프라인에서 제외하도록 한다.\n\nfingerprint 규약(PackageFingerprints):\n- pkg:<sha256(url|args)>          — 패키지 (URL/인수가 바뀌면 새 fingerprint)\n- edgeext:<extensionId>           — Edge 확장 (안정 식별자)\n- p\n[…]\n 재설치\" 체크박스로 일괄 우회 가능\n- 카탈로그 진입 시 PruneStaleFingerprints 로 더 이상 유효하지 않은 항목 청소\n- IUserDataStore 도 Current + 디바운스 저장 모델로 리팩토링 (단일 진실)\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): 패키지 설치 상태 캐시 + 반복 진입 시 자동 skip",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T08:03:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a50ca390d0e0814b5f1be307328c38d69d36caa3",
          "body": "Phase 0~8: TableCloth + Spork 단일 바이너리 통합 + verb 기반 CLI 디스패처 전환.\n\n핵심 변경:\n- 두 .exe → TableCloth.exe (verb 'spork'로 Spork.App 라우팅) + Spork.exe (단독\n  출시 후보, 별도 Spork.slnx)\n- net48 Spork → .NET 10 / WPF / Microsoft.Extensions.Hosting\n- 모듈 라이브러리화: TableCloth.App, Spork.App, TableCloth.Core, Spork.Sandbox\n\n[…]\nr\n  Step으로 적용. 한국 인터넷뱅킹의 보안 SW 로컬 통신 프롬프트 우회.\n- ReloadEdgeStep의 launcher race로 인한 무한 hang을 Process.Kill 트리 종료로\n  교체.\n- 즐겨찾기 별 토글의 mounted 폴더 PNG 재로드 폭주를 ServiceLogoConverter 캐시\n  + 디바운스 SaveAsync로 제거.",
          "is_bot": false,
          "headline": "Merge branch 'feature/unified-binary-verbs'",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T06:28:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c2ec7d7b19da4999e2dd9fa24d7f1fc015727df8",
          "body": "SAC가 Enforce/Evaluation 모드인 호스트에서 샌드박스가 정책을 상속한 뒤\nPrerequisites 단계의 DisableSmartAppControlStep이 citool --refresh를 호출하면,\n커널 CI가 실행 중인 모든 프로세스를 새 정책으로 재평가한다. single-file +\nR2R 게시 + EV 미서명 상태의 TableCloth.exe/Spork는 untrusted로 분류되어\n커널 단에서 강제 종료되며, 이는 managed try/catch로 잡을 수 없어 사용자\n관점에서는 Spork가 그냥 사라지는 회\n[…]\nps/Implementations/DisableSmartAppControlStep.cs 삭제\n- 더 이상 표시되지 않는 Install_DisableSmartAppControl 리소스 문자열 정리\n  (en/ko/Designer.cs)\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(spork): Smart App Control 비활성화를 StartupScript.cmd 단계로 이전",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T06:27:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "37237006a6e0674d8bdb8533cf63dcc31cd51835",
          "body": "설치 흐름이 Config 단계의 ReloadEdgeStep에서 자주 멈춰 사용자가 강제 종료해야\n했던 문제 해결. 두 가지 누적 버그:\n\n1. Chromium 단일 인스턴스 위임 — msedge.exe about:blank로 띄운 핸들은 이미\n   실행 중인 Edge가 있을 경우 위임 직후 종료되는 launcher 프로세스. 진짜 Edge\n   본체는 우리가 잡지 못한 채 살아남아 정책 반영된 fresh 인스턴스가 만들어지지\n   않았다.\n2. TaskCompletionSource race — Process.Start 직후 laun\n[…]\n에\n직전 단계가 기록한 LNA 정책을 모두 새로 읽어 들인다.\n\n종료 polling은 5초 cap으로 hang 가능성 차단. 본 단계의 ctor가 더 이상\nIWebBrowserService 경로를 사용하지 않으므로 키 의존성도 제거.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(spork): ReloadEdgeStep 무한 hang 제거 + 실제 트리 종료로 재작성",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T06:13:13Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "94a83f45a2730b25ef8e4696e1d37ed00bd4f436",
          "body": "한국 인터넷뱅킹/금융 사이트가 안랩 Safe Transaction, INISafe, 금결원 NPKI 등의\n로컬 보안 SW 서버(127.0.0.1:port)에 접근할 때 Edge 138+ 가 \"이 장치에서 다른 앱\n및 서비스에 액세스\" 프롬프트를 띄워 자동화 흐름이 끊기던 문제 해결.\n\nPrerequisites 그룹의 새 step(AllowEdgeLocalNetworkAccessStep)이 샌드박스 단위로\nHKLM\\SOFTWARE\\Policies\\Microsoft\\Edge에 세 정책을 함께 기록:\n\n- LocalNetworkAcces\n[…]\n효력이지만, 일부 Edge 빌드가\nWindows Policy Service 캐시를 참고하는 케이스 대비 best-effort로 gpupdate /force\n/target:computer를 15초 cap으로 함께 호출(실패 시 무시).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(spork): Edge Local Network Access 자동 허용 단계 추가",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T06:12:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "761ec3a6067ac87b9e38857010b66c08deb6fedd",
          "body": "별 토글 시 mounted 호스트 폴더에서 266개 PNG가 UI 스레드 동기 디코드되어\n수백 ms~수 초 freeze 발생하던 문제 해결.\n\n- ServiceLogoConverter: ID별 BitmapImage를 ConcurrentDictionary로 캐시하고\n  IgnoreImageCache 플래그 제거. frozen bitmap이라 스레드 간 안전하게 공유 가능.\n  파일 부재(null) 결과도 negative cache로 추적해 File.Exists 반복 회피.\n- MainWindowViewModel.ToggleFavori\n[…]\n후 백그라운드 SaveAsync. 빠른 연속\n  클릭이 1회 쓰기로 합쳐지고 mounted 폴더 쓰기는 클릭 응답성과 분리.\n- CloneUserData() 스냅샷으로 UI 스레드 변형과 백그라운드 JSON 직렬화 간 race 차단.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(spork): 즐겨찾기 별 토글 freezing 제거",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T05:43:37Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "08819eb4efaa564f5e70bdfd97bb3e5ffc8f2180",
          "body": "부팅 후 LogonCommand의 PowerShell DNS 설정(Get-NetAdapter + Set-DnsClientServerAddress)\n콜드 스타트가 수 초 소모되어 Spork 진입을 지연시키던 문제 해결. batch는 환경 변수\n설정 + exe 실행만 담당하고, DNS/인증서 배치/NPKI 사본화는 Spork.App 진입 시점에\nISandboxBootstrap이 처리(DNS는 fire-and-forget으로 UI 진입을 막지 않음).\n\n부가 정비:\n- 인증서 staging 경로를 App 폴더 하위(<App>/certs)\n[…]\nap 기본 등록\n- TableCloth.exe spork verb 핸들러만 UseSandboxBootstrap()을 호출해 등록 교체\n- Spork.slnx 변경 없음 — 단독 빌드 출력에 Spork.Sandbox.dll 미포함 확인\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "perf(sandbox): StartupScript에서 PowerShell 제거 + sandbox 부팅 로직 Spork로 이전",
          "author_name": "Jung Hyun, Nam",
          "author_login": "rkttu",
          "committed_at": "2026-05-17T05:16:32Z",
          "body_truncated": true,
          "is_coding_agent": true
        }
      ],
      "releases_count": 31,
      "commits_last_year": 298,
      "latest_release_at": "2026-07-18T09:37:50Z",
      "latest_release_tag": "v1.20.6",
      "releases_from_tags": false,
      "days_since_last_push": 1,
      "active_weeks_last_year": 15,
      "days_since_latest_release": 6,
      "mean_days_between_releases": 21.9
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 62,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 60,
      "stars": 1096,
      "watchers": 9,
      "fork_history": {
        "days": [
          {
            "date": "2021-07-16",
            "count": 1
          },
          {
            "date": "2021-07-17",
            "count": 1
          },
          {
            "date": "2021-08-20",
            "count": 2
          },
          {
            "date": "2021-08-23",
            "count": 1
          },
          {
            "date": "2021-10-04",
            "count": 1
          },
          {
            "date": "2022-03-15",
            "count": 1
          },
          {
            "date": "2022-07-17",
            "count": 7
          },
          {
            "date": "2022-07-23",
            "count": 1
          },
          {
            "date": "2022-08-24",
            "count": 1
          },
          {
            "date": "2022-09-13",
            "count": 1
          },
          {
            "date": "2022-11-28",
            "count": 1
          },
          {
            "date": "2023-01-07",
            "count": 1
          },
          {
            "date": "2023-02-24",
            "count": 1
          },
          {
            "date": "2023-03-09",
            "count": 1
          },
          {
            "date": "2023-03-11",
            "count": 1
          },
          {
            "date": "2023-03-13",
            "count": 1
          },
          {
            "date": "2023-04-06",
            "count": 1
          },
          {
            "date": "2023-07-14",
            "count": 1
          },
          {
            "date": "2023-08-08",
            "count": 1
          },
          {
            "date": "2023-08-30",
            "count": 1
          },
          {
            "date": "2023-09-12",
            "count": 1
          },
          {
            "date": "2023-10-08",
            "count": 1
          },
          {
            "date": "2023-10-11",
            "count": 1
          },
          {
            "date": "2023-10-15",
            "count": 2
          },
          {
            "date": "2023-10-25",
            "count": 1
          },
          {
            "date": "2023-11-20",
            "count": 1
          },
          {
            "date": "2023-12-17",
            "count": 1
          },
          {
            "date": "2023-12-30",
            "count": 1
          },
          {
            "date": "2023-12-31",
            "count": 1
          },
          {
            "date": "2024-01-01",
            "count": 1
          },
          {
            "date": "2024-01-02",
            "count": 1
          },
          {
            "date": "2024-01-03",
            "count": 1
          },
          {
            "date": "2024-01-04",
            "count": 1
          },
          {
            "date": "2024-01-09",
            "count": 1
          },
          {
            "date": "2024-01-29",
            "count": 1
          },
          {
            "date": "2024-02-15",
            "count": 1
          },
          {
            "date": "2024-02-23",
            "count": 1
          },
          {
            "date": "2024-04-04",
            "count": 1
          },
          {
            "date": "2024-05-29",
            "count": 1
          },
          {
            "date": "2024-06-11",
            "count": 1
          },
          {
            "date": "2024-06-21",
            "count": 1
          },
          {
            "date": "2024-12-03",
            "count": 1
          },
          {
            "date": "2025-01-25",
            "count": 1
          },
          {
            "date": "2025-02-16",
            "count": 1
          },
          {
            "date": "2025-04-05",
            "count": 1
          },
          {
            "date": "2025-05-09",
            "count": 1
          },
          {
            "date": "2025-06-17",
            "count": 1
          },
          {
            "date": "2025-06-28",
            "count": 1
          },
          {
            "date": "2025-10-31",
            "count": 1
          },
          {
            "date": "2025-12-05",
            "count": 1
          },
          {
            "date": "2025-12-08",
            "count": 1
          },
          {
            "date": "2026-05-21",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 60,
        "total_forks": 60
      },
      "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": [
        "src/Spork.App/Spork.App.csproj",
        "src/Spork.Bootstrapper/Spork.Bootstrapper.csproj",
        "src/Spork.Sandbox/Spork.Sandbox.csproj",
        "src/Spork.Test/Spork.Test.csproj",
        "src/Spork/Spork.csproj",
        "src/TableCloth.App/TableCloth.App.csproj",
        "src/TableCloth.Core/TableCloth.Core.csproj",
        "src/TableCloth.Test/TableCloth.Test.csproj",
        "src/TableCloth/TableCloth.csproj"
      ],
      "largest_source_bytes": 88947,
      "source_files_sampled": 260,
      "oversized_source_files": 1,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [],
      "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": 28,
        "direct_affected_count": 0
      },
      "ecosystems": [],
      "dependencies": [
        {
          "name": "AsyncAwaitBestPractices.MVVM",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "CommunityToolkit.Mvvm",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Configuration",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Configuration.Binder",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Configuration.CommandLine",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Configuration.EnvironmentVariables",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Configuration.Json",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Configuration.UserSecrets",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.DependencyInjection",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Hosting",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Http",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Logging",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Logging.Console",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Logging.Debug",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Logging.EventLog",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Xaml.Behaviors.Wpf",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Sentry",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Sentry.Serilog",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Serilog",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Serilog.Extensions.Logging",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "System.CommandLine",
          "manifest": "src/Spork.App/Spork.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.DependencyInjection",
          "manifest": "src/Spork.Sandbox/Spork.Sandbox.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Hosting",
          "manifest": "src/Spork.Sandbox/Spork.Sandbox.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Logging",
          "manifest": "src/Spork.Sandbox/Spork.Sandbox.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.NET.Test.Sdk",
          "manifest": "src/Spork.Test/Spork.Test.csproj",
          "ecosystem": "nuget",
          "version_constraint": "18.0.1"
        },
        {
          "name": "MSTest.TestAdapter",
          "manifest": "src/Spork.Test/Spork.Test.csproj",
          "ecosystem": "nuget",
          "version_constraint": "4.0.2"
        },
        {
          "name": "MSTest.TestFramework",
          "manifest": "src/Spork.Test/Spork.Test.csproj",
          "ecosystem": "nuget",
          "version_constraint": "4.0.2"
        },
        {
          "name": "Microsoft.Extensions.DependencyInjection",
          "manifest": "src/Spork/Spork.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Hosting",
          "manifest": "src/Spork/Spork.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Sentry",
          "manifest": "src/Spork/Spork.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "AsyncAwaitBestPractices.MVVM",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.DependencyInjection",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Hosting",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Http",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Xaml.Behaviors.Wpf",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "PnPeople.Security",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Sentry.Serilog",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Serilog.Extensions.Logging",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Serilog.Sinks.File",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "System.CommandLine",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "System.Management",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Velopack",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "XamlRadialProgressBar",
          "manifest": "src/TableCloth.App/TableCloth.App.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "CommunityToolkit.Mvvm",
          "manifest": "src/TableCloth.Core/TableCloth.Core.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "System.Security.AccessControl",
          "manifest": "src/TableCloth.Core/TableCloth.Core.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "System.Text.Json",
          "manifest": "src/TableCloth.Core/TableCloth.Core.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.NET.Test.Sdk",
          "manifest": "src/TableCloth.Test/TableCloth.Test.csproj",
          "ecosystem": "nuget",
          "version_constraint": "18.0.1"
        },
        {
          "name": "MSTest.TestAdapter",
          "manifest": "src/TableCloth.Test/TableCloth.Test.csproj",
          "ecosystem": "nuget",
          "version_constraint": "4.0.2"
        },
        {
          "name": "MSTest.TestFramework",
          "manifest": "src/TableCloth.Test/TableCloth.Test.csproj",
          "ecosystem": "nuget",
          "version_constraint": "4.0.2"
        },
        {
          "name": "Microsoft.Extensions.DependencyInjection",
          "manifest": "src/TableCloth/TableCloth.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Microsoft.Extensions.Hosting",
          "manifest": "src/TableCloth/TableCloth.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        },
        {
          "name": "Velopack",
          "manifest": "src/TableCloth/TableCloth.csproj",
          "ecosystem": "nuget",
          "version_constraint": null
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "AsyncAwaitBestPractices.MVVM",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "CommunityToolkit.Mvvm",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Configuration",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Configuration.Binder",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Configuration.CommandLine",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Configuration.EnvironmentVariables",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Configuration.Json",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Configuration.UserSecrets",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.DependencyInjection",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Hosting",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Http",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Logging",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Logging.Console",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Logging.Debug",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Extensions.Logging.EventLog",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Microsoft.Xaml.Behaviors.Wpf",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "PnPeople.Security",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Sentry",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Sentry.Serilog",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Serilog",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Serilog.Extensions.Logging",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Serilog.Sinks.File",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "System.CommandLine",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "System.Management",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "System.Security.AccessControl",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "System.Text.Json",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "Velopack",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          },
          {
            "name": "XamlRadialProgressBar",
            "direct": true,
            "version": null,
            "ecosystem": "nuget"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 28,
        "direct_count": 28,
        "indirect_count": 0
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 57,
        "open_issues": 1,
        "closed_ratio": 0.995,
        "closed_issues": 199,
        "closed_unmerged_prs": 4
      },
      "bus_factor": 1,
      "bot_contributors": 2,
      "top_contributors": [
        {
          "type": "User",
          "login": "rkttu",
          "commits": 1065,
          "avatar_url": "https://avatars.githubusercontent.com/u/1297346?v=4"
        },
        {
          "type": "User",
          "login": "ChJR",
          "commits": 14,
          "avatar_url": "https://avatars.githubusercontent.com/u/7029007?v=4"
        },
        {
          "type": "User",
          "login": "level120",
          "commits": 12,
          "avatar_url": "https://avatars.githubusercontent.com/u/10791961?v=4"
        },
        {
          "type": "User",
          "login": "atawLee",
          "commits": 8,
          "avatar_url": "https://avatars.githubusercontent.com/u/34878017?v=4"
        },
        {
          "type": "User",
          "login": "papavhub",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/67986703?v=4"
        },
        {
          "type": "User",
          "login": "qb20nh",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/1734074?v=4"
        },
        {
          "type": "User",
          "login": "leedonggyu1848",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/53461960?v=4"
        },
        {
          "type": "User",
          "login": "Hyolog",
          "commits": 2,
          "avatar_url": "https://avatars.githubusercontent.com/u/14173879?v=4"
        },
        {
          "type": "User",
          "login": "edoko",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/1365682?v=4"
        },
        {
          "type": "User",
          "login": "oosulz",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/50573818?v=4"
        }
      ],
      "contributors_sampled": 14,
      "top_contributor_share": 0.957
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": false,
      "ci_workflows": [
        "build.yml",
        "bump_catalog_submodule.yml",
        "discord_release.yml",
        "winget_publish.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": true,
      "has_linter_config": false,
      "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": 3,
            "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": "14 out of 14 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/11 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 7 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 30 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": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 10,
            "reason": "SAST tool is run on all commits",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 10,
            "reason": "security policy file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "6da57ba1235135bdac9c7c4f8bd1689e0208a62c",
        "ran_at": "2026-07-25T00:19:58Z",
        "aggregate_score": 6,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": true,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-23T14:23:42Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-23T14:08:25Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 296,
          "created_at": "2026-07-06T15:01:37Z",
          "last_comment_at": null,
          "last_comment_author": null
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/yourtablecloth/TableCloth",
    "host": "github.com",
    "name": "TableCloth",
    "owner": "yourtablecloth"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 64,
      "inputs": {
        "security": 60,
        "vitality": 80,
        "community": 60,
        "governance": 57,
        "engineering": 60
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 80,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "commits_last_year": 298,
              "human_commit_share": 0.92,
              "days_since_last_push": 1,
              "active_weeks_last_year": 15
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 1 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "15/52 weeks with commits",
                "points": 10.4,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 15
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "298 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 298
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 30 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": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 31,
              "latest_release_tag": "v1.20.6",
              "releases_from_tags": false,
              "days_since_latest_release": 6,
              "mean_days_between_releases": 21.9
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "31 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 31
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 6 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~21.9 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 21.9
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "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": 1,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 1 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 1
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "moderate",
        "name": "Community & Adoption",
        "value": 60,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "moderate",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 69,
            "inputs": {
              "forks": 60,
              "stars": 1096,
              "watchers": 9,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "1,096 stars",
                "points": 49.3,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 1096
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "60 forks",
                "points": 14.8,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 60
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "9 watchers",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 9
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (AGPL-3.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "AGPL-3.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 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
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 57,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "at_risk",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 34,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 14,
              "top_contributor_share": 0.957
            },
            "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 96% of commits",
                "points": 1,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 96
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "14 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 14
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 7 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 82,
            "inputs": {
              "merged_prs": 57,
              "open_issues": 1,
              "closed_issues": 199,
              "issue_closed_ratio": 0.995,
              "closed_unmerged_prs": 4
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "100% of issues closed",
                "points": 46.5,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "57/61 decided PRs merged",
                "points": 35.7,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 57,
                      "decided": 61
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/11 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "moderate",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "followers": 39,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "yourtablecloth",
              "public_repos": 16,
              "account_age_days": 1798
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "39 followers of yourtablecloth",
                "points": 11.5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 39,
                      "login": "yourtablecloth"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "16 public repos, account ~4 yr old",
                "points": 18.8,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 16
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 4
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 60,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_ci": true,
              "has_tests": false,
              "has_editorconfig": true,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "4 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "14 out of 14 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": [
                "hacktoberfest",
                "csharp",
                "dotnet",
                "sdk",
                "windows-10",
                "windows-11"
              ],
              "has_wiki": false,
              "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": "6 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 6
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 60,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 6
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection is not maximal on development and all release branches",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "14 out of 14 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/11 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 7 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 30 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": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is run on all commits",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 12
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "at_risk",
        "name": "AI Readiness",
        "value": 48,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 1,
              "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": "92 of 92 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 92,
                      "sampled": 92
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 34,
            "inputs": {
              "has_nix": false,
              "has_tests": false,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.86,
              "toolchain_manifests": [
                "src/Spork.App/Spork.App.csproj",
                "src/Spork.Bootstrapper/Spork.Bootstrapper.csproj",
                "src/Spork.Sandbox/Spork.Sandbox.csproj",
                "src/Spork.Test/Spork.Test.csproj",
                "src/Spork/Spork.csproj",
                "src/TableCloth.App/TableCloth.App.csproj",
                "src/TableCloth.Core/TableCloth.Core.csproj",
                "src/TableCloth.Test/TableCloth.Test.csproj",
                "src/TableCloth/TableCloth.csproj"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "src/Spork.App/Spork.App.csproj, src/Spork.Bootstrapper/Spork.Bootstrapper.csproj, src/Spork.Sandbox/Spork.Sandbox.csproj (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "src/Spork.App/Spork.App.csproj, src/Spork.Bootstrapper/Spork.Bootstrapper.csproj, src/Spork.Sandbox/Spork.Sandbox.csproj"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "C# (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "C#"
                    }
                  }
                ],
                "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": "86 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 86,
                      "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": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "C#",
              "largest_source_bytes": 88947,
              "source_files_sampled": 260,
              "oversized_source_files": 1
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "C# (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "C#"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "1/260 source files over 60KB",
                "points": 54.8,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 260,
                      "oversized": 1
                    }
                  }
                ],
                "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-25T00:20:23.909769Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/y/yourtablecloth/TableCloth.svg",
  "full_name": "yourtablecloth/TableCloth",
  "license_state": "standard",
  "license_spdx": "AGPL-3.0"
}

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

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

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