Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.26.0 · метрики 1.13.0 · 2026-07-22 15:11 UTC

lambdadevelopment / lambda-erp

Open-source AI-native ERP. Accounting, inventory, analytics — all through chat.

Python · TypeScriptApache-2.0★ 20 зірок⑂ 5 форківз квіт. 2026 р.Переглянути на GitHub ↗

lambdadevelopment/lambda-erp має індекс здоров’я 53 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (83/100), найнижчий — Sustainability & Governance (34/100). Останнє оновлення було 2 дні тому. Більшість нещодавньої роботи виконує один учасник.

53
загалом / 100
Помірний

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє середнє; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 49 («Під ризиком»). Готовність до ШІ не входить до індексу.

53
Відмінний85-100Зразковий; відповідає практично всім перевіреним критеріям
Добрий70-84Здоровий; незначні прогалини
Помірний50-69Прийнятний, але з помітними прогалинами; рекомендовано перевірку
У зоні ризику30-49Суттєві слабкі місця; впровадження потребує обережності
Критичний1-29Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Власність

Lambda Automation DevelopmentОрганізація
1 підписник3 публічні репозиторіїз лип. 2024 р.

За цим репозиторієм стоїть організація — спільна, підзвітна опіка, здатна пережити будь-якого окремого мейнтейнера.

Пакетні екосистеми

РеєстрПакетВерсіяЗавантажень / місВерсіїОстання публікація
PyPIlambda-erp0.3.44 886635 днів тому
npm@lambda-development/erp-core0.3.46 160615 днів тому

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

83Добрий · 22% загального індексу
Як обчислюється оцінка
36/36Свіжість push — останній push 2 дн. тому
7.6/36Ритм комітів — 11/52 тижнів із комітами
18/18Обсяг комітів — 148 комітів за останній рік
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Використані вхідні дані
commits_last_year148
human_commit_share1
days_since_last_push2
active_weeks_last_year11
Як обчислюється оцінка
27/27Випускає релізи — опубліковано 60 релізів
36/36Свіжість релізів — останній реліз 5 дн. тому
27/27Ритм релізів — реліз кожні ~0,2 дн.
0/10OpenSSF Scorecard: Signed-Releases — немає даних
Використані вхідні дані
releases_count60
latest_release_tagv0.3.4
releases_from_tagsні
days_since_latest_release5
mean_days_between_releases0,2
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: Signed-Releases. Залишкові ваги перенормовано.

Спільнота та впровадження

Чи має проєкт користувачів, завантаження, увагу та влаштовані умови для контриб’юторів?

45У зоні ризику · 18% загального індексу
Як обчислюється оцінка
20.7/60Зірки — 20 зірок
5/25Форки — 5 форків
0/15Спостерігачі — 0 спостерігачів
Використані вхідні дані
forks5
stars20
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (Apache-2.0)
0/18Настанови CONTRIBUTING
0/13.5Кодекс поведінки
0/7.2Шаблон issue
0/6.3Шаблон PR
Використані вхідні дані
has_readmeтак
has_licenseтак
has_contributingні
has_issue_templateні
has_code_of_conductні
has_pull_request_templateні
Як обчислюється оцінка
53.9/80Щомісячні завантаження — 11 046 завантажень/місяць у npm, pypi
0/20Залежні пакети в реєстрі — ця екосистема цього не повідомляє
Використані вхідні дані
packageslambda-erp, @lambda-development/erp-core
dependents
ecosystemsnpm, pypi
total_downloads
monthly_downloads11 046
Виключено з оцінювання (немає даних або не застосовно): Залежні пакети в реєстрі. Залишкові ваги перенормовано.

Сталість та врядування

Чи переживе проєкт своїх людей — бас-фактор, реактивність, хто за ним стоїть і як супроводжуються пакети?

34У зоні ризику · 24% загального індексу
Як обчислюється оцінка
9/54Бас-фактор — на 1 контриб’ютор(ів) припадає половина всіх комітів
0/22.5Розподіл комітів — головний контриб’ютор — автор 100% комітів
1.4/13.5Широта контриб’юторів — 1 контриб’юторів
3/10OpenSSF Scorecard: Contributors — project has 1 contributing companies or organizations -- score normalized to 3
Використані вхідні дані
bus_factor1
contributors_sampled1
top_contributor_share1
Як обчислюється оцінка
0/46.8Вирішення issue — немає issue або даних
0/38.3Прийняття PR — немає вирішених pull request-ів або даних
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Використані вхідні дані
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs0
Виключено з оцінювання (немає даних або не застосовно): Вирішення issue, Прийняття PR. Залишкові ваги перенормовано.

Власність та опіка

41У зоні ризику
Як обчислюється оцінка
30/30Підтримка власника — у власності організації
0/20Верифікований домен
2.2/25Охоплення власника — 1 підписників у lambdadevelopment
8.4/25Послужний список — 3 публічних репозиторіїв, вік облікового запису ~2 р.
Використані вхідні дані
followers1
owner_typeOrganization
is_verified
owner_loginlambdadevelopment
public_repos3
account_age_days742

Супровід пакетів

100Відмінний
Як обчислюється оцінка
25/25Опубліковано й доступно — 2 пакет(ів) у npm, pypi
35/35Свіжість публікацій — остання публікація 5 дн. тому
20/20Історія версій — 63 опублікованих версій
20/20Не застарілий — активний, не deprecated і не yanked
Використані вхідні дані
packageslambda-erp, @lambda-development/erp-core
ecosystemsnpm, pypi
any_deprecatedні
min_days_since_publish5

Інженерна якість

Чи наявні базові інженерні практики та документація?

66Помірний · 20% загального індексу
Як обчислюється оцінка
24/24Процеси CI — 4 процес(ів) CI
24/24Наявні тести
0/16Конфігурація лінтера
0/9.6Pre-commit-хуки
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — немає даних
Використані вхідні дані
has_ciтак
has_testsтак
has_editorconfigні
has_linter_configні
has_precommit_configні
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: CI-Tests. Залишкові ваги перенормовано.
Як обчислюється оцінка
30/30README
25/25Каталог документації
0/15Сайт документації / домашня сторінка
10/10Опис репозиторію
0/10Теми
10/10Wiki
Використані вхідні дані
topics
has_wikiтак
homepage
has_readmeтак
has_docs_dirтак
has_descriptionтак

Безпека

Чи міцні видимі практики безпеки й ланцюга постачання, без непослабленої пов’язаності з юрисдикціями високого ризику?

36У зоні ризику · 16% загального індексу

Стан безпеки

36У зоні ризику
Як обчислюється оцінка
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — немає даних
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0.8/2.5Contributors — project has 1 contributing companies or organizations -- score normalized to 3
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Ліцензія — license file detected
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
5/5Packaging — packaging workflow detected
0.5/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 1
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — немає даних
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
0/7.5Vulnerabilities — 11 existing vulnerabilities detected
Використані вхідні дані
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate3,6
Виключено з оцінювання (немає даних або не застосовно): ci_tests, signed_releases. Залишкові ваги перенормовано.

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Незалежний, експериментальний бейдж — вага 0.0, тож він подається окремо і не впливає на загальний індекс здоров'я.

70Добрий · 0% загального індексу
Як обчислюється оцінка
45/45Інструкції для агентів — CLAUDE.md
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 92 з 100 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,92
agent_instruction_filesCLAUDE.md
agent_instruction_max_bytes1 598
Як обчислюється оцінка
0/18Розгортання однією командою
22/22Автоматизовані тести
0/11Конфігурація лінтера / форматера
11/11Статична перевірка типів — frontend/tsconfig.json
10/10Відтворюване середовище — Dockerfile, lockfile
10/10Підтверджена практика роботи з агентами — 78 з останніх 100 комітів створено агентом або з його зазначенням
0/8Автоматизоване супроводження — автоматичних оновлень залежностей не виявлено
1/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 1
Використані вхідні дані
has_nixні
has_testsтак
lockfilespackage-lock.json
has_dockerfileтак
typed_languageні
bootstrap_files
has_devcontainerні
has_linter_configні
typecheck_configsfrontend/tsconfig.json
agent_commit_share0,78
toolchain_manifests
dependency_bot_commit_share0
Як обчислюється оцінка
27/45Типізований код — Python з конфігурацією перевірки типів (frontend/tsconfig.json)
53.9/55Керовані розміри файлів — 3/145 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languagePython
largest_source_bytes181 453
source_files_sampled145
oversized_source_files3

Ключові факти

20зірок GitHub
1контриб'юторів
148комітів за останні 12 місяців
2днів від останнього пушу
60релізів
1бас-фактор
0відкритих issue
npm, PyPIпакетних екосистем

Попередження щодо збору даних

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index pypi:lambda-erp@0.3.4; advisories assessed against the repository dependency graph instead

Докладніше

Історія зірок і форків 0 ★ / 5 ⇿
0Зірки
5Форки
37Релізи

Коли додано кожну зірку й форк — зібрано з GitHub і згруповано за днями. Кумулятивне зростання розміщено просто над денними додаваннями, з яких воно складається, тож їх видно одне проти одного: рівномірне органічне накопичення виглядає зовсім інакше, ніж різкий короткочасний сплеск. Там, де цю різницю можна виміряти, її подано як автентичність росту.

12345522026-052026-062026-07
Мажорні 0Мінорні 0Патчі 37
OpenSSF Scorecard 3.6 / 10
3.6сукупно

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-07-22 15:11 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
н/дCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
3Contributorsproject has 1 contributing companies or organizations -- score normalized to 3
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
10Packagingpackaging workflow detected
1Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 1
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
н/дSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
0Vulnerabilities11 existing vulnerabilities detected
Прямі залежності 16
РеєстрПакетОбмеження версіїМаніфест
npm@fontsource/inter^5.2.8frontend/package.json
PyPIfastapi>=0.115pyproject.toml
PyPIuvicorn>=0.30pyproject.toml
PyPIpython-multipart>=0.0.9pyproject.toml
PyPIpydantic>=2.0pyproject.toml
PyPIanthropic>=0.40pyproject.toml
PyPIopenai>=1.0pyproject.toml
PyPIhttpx>=0.27pyproject.toml
PyPIpython-dotenv>=1.0pyproject.toml
PyPIpython-dateutil>=2.8pyproject.toml
PyPIpython-jose>=3.3pyproject.toml
PyPIbcrypt>=5pyproject.toml
PyPIJinja2>=3.1pyproject.toml
PyPIweasyprint>=62.0pyproject.toml
PyPIpypdf>=4.0pyproject.toml
PyPIholidays>=0.40pyproject.toml
Усі залежності не зібрано

Не вдалося зібрати розв'язаний набір залежностей для цього звіту: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1886,
      "has_wiki": true,
      "homepage": null,
      "languages": {
        "CSS": 4229,
        "HCL": 22484,
        "HTML": 14447,
        "Python": 1085771,
        "Dockerfile": 2566,
        "JavaScript": 81,
        "TypeScript": 507245
      },
      "pushed_at": "2026-07-20T11:07:41Z",
      "created_at": "2026-04-23T13:19:56Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-21T15:23:27Z",
      "description": "Open-source AI-native ERP. Accounting, inventory, analytics — all through chat.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "Apache-2.0",
      "default_branch": "master",
      "license_spdx_raw": "Apache-2.0",
      "primary_language": "Python",
      "significant_languages": [
        "Python",
        "TypeScript"
      ]
    },
    "owner": {
      "blog": "https://lambda.dev",
      "name": "Lambda Automation Development",
      "type": "Organization",
      "login": "lambdadevelopment",
      "company": null,
      "location": null,
      "followers": 1,
      "avatar_url": "https://avatars.githubusercontent.com/u/175140732?v=4",
      "created_at": "2024-07-09T15:52:35Z",
      "is_verified": null,
      "public_repos": 3,
      "account_age_days": 742
    },
    "license": {
      "state": "standard",
      "spdx_id": "Apache-2.0",
      "raw_spdx": "Apache-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.3.4",
          "kind": "patch",
          "published_at": "2026-07-17T13:24:50Z"
        },
        {
          "tag": "v0.3.3",
          "kind": "patch",
          "published_at": "2026-07-17T12:15:01Z"
        },
        {
          "tag": "v0.3.2",
          "kind": "patch",
          "published_at": "2026-07-17T11:58:37Z"
        },
        {
          "tag": "v0.3.1",
          "kind": "patch",
          "published_at": "2026-07-17T11:03:16Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2026-07-16T10:28:05Z"
        },
        {
          "tag": "v0.2.6",
          "kind": "patch",
          "published_at": "2026-07-16T09:14:02Z"
        },
        {
          "tag": "v0.2.5",
          "kind": "patch",
          "published_at": "2026-07-15T20:47:57Z"
        },
        {
          "tag": "v0.2.4",
          "kind": "patch",
          "published_at": "2026-07-15T20:32:15Z"
        },
        {
          "tag": "v0.2.3",
          "kind": "patch",
          "published_at": "2026-07-15T18:05:05Z"
        },
        {
          "tag": "v0.2.2",
          "kind": "patch",
          "published_at": "2026-07-15T17:09:27Z"
        },
        {
          "tag": "v0.2.1",
          "kind": "patch",
          "published_at": "2026-07-15T16:35:53Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2026-07-15T16:11:56Z"
        },
        {
          "tag": "v0.1.49",
          "kind": "patch",
          "published_at": "2026-07-14T17:32:00Z"
        },
        {
          "tag": "v0.1.48",
          "kind": "patch",
          "published_at": "2026-07-14T17:29:29Z"
        },
        {
          "tag": "v0.1.47",
          "kind": "patch",
          "published_at": "2026-07-14T15:42:57Z"
        },
        {
          "tag": "v0.1.46",
          "kind": "patch",
          "published_at": "2026-07-14T15:37:20Z"
        },
        {
          "tag": "v0.1.45",
          "kind": "patch",
          "published_at": "2026-07-14T14:30:59Z"
        },
        {
          "tag": "v0.1.44",
          "kind": "patch",
          "published_at": "2026-07-14T13:41:19Z"
        },
        {
          "tag": "v0.1.43",
          "kind": "patch",
          "published_at": "2026-07-14T10:23:05Z"
        },
        {
          "tag": "v0.1.42",
          "kind": "patch",
          "published_at": "2026-07-14T10:00:23Z"
        },
        {
          "tag": "v0.1.41",
          "kind": "patch",
          "published_at": "2026-07-14T09:56:52Z"
        },
        {
          "tag": "v0.1.40",
          "kind": "patch",
          "published_at": "2026-07-14T09:53:40Z"
        },
        {
          "tag": "v0.1.39",
          "kind": "patch",
          "published_at": "2026-07-14T09:32:02Z"
        },
        {
          "tag": "v0.1.38",
          "kind": "patch",
          "published_at": "2026-07-13T09:20:19Z"
        },
        {
          "tag": "v0.1.37",
          "kind": "patch",
          "published_at": "2026-07-10T20:45:43Z"
        },
        {
          "tag": "v0.1.36",
          "kind": "patch",
          "published_at": "2026-07-10T17:14:53Z"
        },
        {
          "tag": "v0.1.35",
          "kind": "patch",
          "published_at": "2026-07-01T17:58:22Z"
        },
        {
          "tag": "v0.1.34",
          "kind": "patch",
          "published_at": "2026-07-01T16:48:45Z"
        },
        {
          "tag": "v0.1.33",
          "kind": "patch",
          "published_at": "2026-07-01T16:21:11Z"
        },
        {
          "tag": "v0.1.32",
          "kind": "patch",
          "published_at": "2026-07-01T16:10:51Z"
        },
        {
          "tag": "v0.1.31",
          "kind": "patch",
          "published_at": "2026-06-25T13:37:33Z"
        },
        {
          "tag": "v0.1.30",
          "kind": "patch",
          "published_at": "2026-06-24T15:36:45Z"
        },
        {
          "tag": "v0.1.29",
          "kind": "patch",
          "published_at": "2026-06-24T15:13:16Z"
        },
        {
          "tag": "v0.1.28",
          "kind": "patch",
          "published_at": "2026-06-24T14:15:22Z"
        },
        {
          "tag": "v0.1.27",
          "kind": "patch",
          "published_at": "2026-06-24T09:34:51Z"
        },
        {
          "tag": "v0.1.26",
          "kind": "patch",
          "published_at": "2026-06-24T08:58:01Z"
        },
        {
          "tag": "v0.1.25",
          "kind": "patch",
          "published_at": "2026-06-23T21:31:19Z"
        },
        {
          "tag": "v0.1.24",
          "kind": "patch",
          "published_at": "2026-06-22T07:47:31Z"
        },
        {
          "tag": "v0.1.23",
          "kind": "patch",
          "published_at": "2026-06-20T17:25:02Z"
        },
        {
          "tag": "v0.1.22",
          "kind": "patch",
          "published_at": "2026-06-20T17:12:51Z"
        },
        {
          "tag": "v0.1.21",
          "kind": "patch",
          "published_at": "2026-06-20T16:19:16Z"
        },
        {
          "tag": "v0.1.20",
          "kind": "patch",
          "published_at": "2026-06-19T11:49:03Z"
        },
        {
          "tag": "v0.1.19",
          "kind": "patch",
          "published_at": "2026-06-17T17:55:00Z"
        },
        {
          "tag": "v0.1.18",
          "kind": "patch",
          "published_at": "2026-06-05T11:10:33Z"
        },
        {
          "tag": "v0.1.17",
          "kind": "patch",
          "published_at": "2026-06-05T08:51:23Z"
        },
        {
          "tag": "v0.1.16",
          "kind": "patch",
          "published_at": "2026-06-05T08:33:38Z"
        },
        {
          "tag": "v0.1.15",
          "kind": "patch",
          "published_at": "2026-06-04T22:41:22Z"
        },
        {
          "tag": "v0.1.14",
          "kind": "patch",
          "published_at": "2026-06-04T18:09:14Z"
        },
        {
          "tag": "v0.1.13",
          "kind": "patch",
          "published_at": "2026-06-04T17:02:12Z"
        },
        {
          "tag": "v0.1.12",
          "kind": "patch",
          "published_at": "2026-06-04T13:13:10Z"
        },
        {
          "tag": "v0.1.11",
          "kind": "patch",
          "published_at": "2026-06-04T12:34:40Z"
        },
        {
          "tag": "v0.1.10",
          "kind": "patch",
          "published_at": "2026-06-04T09:45:15Z"
        },
        {
          "tag": "v0.1.9",
          "kind": "patch",
          "published_at": "2026-06-04T07:57:20Z"
        },
        {
          "tag": "v0.1.8",
          "kind": "patch",
          "published_at": "2026-06-03T22:31:14Z"
        },
        {
          "tag": "v0.1.7",
          "kind": "patch",
          "published_at": "2026-06-03T17:51:03Z"
        },
        {
          "tag": "v0.1.6",
          "kind": "patch",
          "published_at": "2026-06-03T17:33:47Z"
        },
        {
          "tag": "v0.1.5",
          "kind": "patch",
          "published_at": "2026-06-03T16:33:13Z"
        },
        {
          "tag": "v0.1.4",
          "kind": "patch",
          "published_at": "2026-06-03T15:22:18Z"
        },
        {
          "tag": "v0.1.3",
          "kind": "patch",
          "published_at": "2026-06-03T14:47:29Z"
        },
        {
          "tag": "v0.1.2",
          "kind": "patch",
          "published_at": "2026-05-26T21:48:10Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "39068a6e52f556509734450d296da9a3e65cc4a2",
          "body": null,
          "is_bot": false,
          "headline": "Update LICENSE",
          "author_name": "Jonathan C. Frei",
          "author_login": "jcfrei",
          "committed_at": "2026-07-20T11:07:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b7b8c193fac0c45a886a7de62d17ed76ed49fbe3",
          "body": "Deactivating the chat API in Settings now shows a confirmation dialog (enabling\nstays instant) that makes clear the API keys are preserved — the flag only gates\nthe API surface; keys keep working when it's re-enabled. Frontend-only\n(settings.tsx + en/de/fr).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.3.4: confirm dialog before deactivating the chat API",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-17T13:23:53Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "350101b033e3bf95085fa5678149521ebd1a7d38",
          "body": "…ds from chat\n\nsearch_masters hides disabled records by default (good — don't book to retired\naccounts), but they were unreachable: no way to find a disabled account to\nre-enable it (catch-22) or answer \"what's disabled\". Adds an optional\ninclude_disabled flag (default false) applied to the no-query\n[…]\nuzzy paths, plus a prompt nudge to retry with it when an expected record isn't\nfound. Mirrors the existing list_masters include_disabled param.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.3.3: search_masters include_disabled — reach disabled recor…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-17T12:14:04Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8d90394b3bbb0ca018468bb43fe35c8a8b043796",
          "body": "…ol flag updates; anti-fabrication prompt\n\n- JournalEntry._normalize_amounts back-fills base debit/credit <-> *_in_account_currency\n  so a JE created with amounts only in the account-currency fields (the chat path)\n  actually posts; on_submit rejects a JE that would post no non-zero GL lines.\n- _nor\n[…]\nmpt: confirm actions from the tool result before claiming success;\n  no master rename exists; verify a field exists before saying it's missing.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.3.2: journal entries post from account-currency amounts; bo…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-17T11:57:30Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "407f4b89aaccdb0640b9f76aa561e8a308ab6353",
          "body": "search_masters no longer hard-caps at 20 results: the chat can pass an optional\n`limit` (omit for no cap), so listing accounts returns the whole chart of\naccounts instead of a silently-truncated 20. Applies to the no-query listing,\nsubstring match, and fuzzy fallback. Backend-only; frontend version bumped to\nkeep the shared version in lockstep. Rebased onto 0.3.0 (Apache relicense).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.3.1: uncap master search (LLM-set limit; omit = all)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-17T11:02:05Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "aec917afd71ed995eed7ac639d673eaa0fc25dde",
          "body": "First Apache-2.0-licensed release of both packages (lambda-erp on PyPI,\n@lambda-development/erp-core on npm). Adds frontend/LICENSE so the npm\ntarball ships a license file. Releases through 0.2.6 remain MIT.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.3.0: relicense from MIT to Apache License 2.0",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-07-16T10:27:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "20aee90659269f6e3f589775ed0256f68e589c97",
          "body": "index.html was returned with no Cache-Control, so browsers heuristically\ncached the shell and a normal reload could load an old shell pointing at\nprevious-build asset URLs — requiring a hard-refresh. Serve it no-cache so\nthe shell always revalidates (304 when unchanged). Also serve the\ncontent-hashe\n[…]\n a 1y max-age so reloads skip asset\nrevalidation entirely — net fewer requests, not more. Bump 0.2.5 -> 0.2.6\n(both packages version together).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(web): stop serving a stale SPA shell on soft refresh",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-16T09:12:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "10fc84adf7c38a0b9aa1d0c2273d06768de804af",
          "body": "0.2.4 fixed /account/tree, but the CoA page the GUI renders is the\n/reports/chart-of-accounts report, which still listed disabled accounts\n(shown as \"disabled\"). It now hides them by default too, with the same\nprune rule (balances still roll up over disabled descendants; a disabled\ngroup with an enabled descendant is kept). include_disabled=true shows them.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.2.5: hide disabled accounts in the Chart of Accounts report",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T20:47:04Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "3a316b6fa666f69a2a74aaf524d001cf0a9643c6",
          "body": "/account/tree now omits disabled accounts by default (they already drop out\nof account pickers), so a retired account leaves the CoA view instead of\nlingering as clutter. A disabled group is still shown when it has an enabled\ndescendant, so an active account is never hidden behind a disabled parent.\ninclude_disabled=true shows them; each node now carries a disabled flag.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.2.4: hide disabled accounts in Chart of Accounts tree",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T20:31:10Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cb50615c1a9ca61f992fff94091cd1c1b453cb66",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.2.3: German DATEV SKR03/SKR04 localization packs",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T18:04:00Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9f39496b14ff5061e23b03607f2766792cfb6577",
          "body": "First use of the country[.variant] pack axis: two Germany charts registered\nunder country=\"de\" — de.skr03 (process-ordered, the most common German SME\nchart, and the default for a bare \"de\") and de.skr04 (balance-sheet-ordered,\nDATEV's recommendation for new companies). Each is a curated ~70-account\n[…]\nUpdates the chat tool descriptions, CHANGELOG [Unreleased], README, and the\ncontributor doc (de_skr03/04 now the multi-variant worked example).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(setup): add German DATEV SKR03/SKR04 localization packs",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T17:47:11Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "90687f45c891e197efa1233f1f431d3aa8230f6f",
          "body": "…at bold-heading fix\n\nCompany setup now converges toward the desired chart instead of refusing when\nthe company already exists:\n- Accounts: create only what's missing (skip existing by name, no PK failure);\n  parents-then-children so a partial chart completes.\n- Defaults: fill only empty company def\n[…]\ntead of being mangled into a `*` bullet.\n\nCloses the guided-setup dead-end seen when a company pre-existed with stray\naccounts (chat 2527ebc9).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.2.2: idempotent company setup (converge, don't refuse) + ch…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T17:08:12Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2ae9ecd2c1f6d50879c18fc92b50a894e52087cd",
          "body": "The markdown list detector matched any line starting with `*`, so a bold\nheading like `**Grundlage**` had its first star stripped and emitted as a `•`\nbullet, leaving `*Grundlage**` unrendered. Require whitespace after the list\nmarker (`- `, `* `, `• `) so `**bold**` (star-star, no space) falls through to\nnormal inline rendering. Real bullets are unaffected.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(chat): render bold lines instead of mis-parsing them as bullets",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T16:45:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "63cf4bb753f1315b06b483f43c48a3e153dc55cf",
          "body": "… line breaks\n\n- Sector-profile overlay accounts are created in the localization pack's language\n  (LocalizationPack.language). On the Swiss (German) chart they now read in German\n  (Beratungserlöse, Aufwand für Fremdleistungen, …) via per-account i18n names;\n  generic stays English. Engine remaps p\n[…]\n line breaks in the user's own message bubble (whitespace-pre-wrap).\n- Tests cover German overlay names + the services default resolving on CH.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.2.1: localize sector accounts + fix services default + chat…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T16:31:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1ee06eb0870848895ebd5b84edd19dc193a0044f",
          "body": "Add lambda_erp/accounting/setup/ — a three-layer chart-of-accounts builder:\na universal account_type spine, pluggable localization packs keyed\ncountry[.variant] (registry + permanent generic fallback), and seven\njurisdiction-independent sector profiles that attach accounts to pack anchors,\nnever to \n[…]\nt_company_setup.py\n  (self-contained) + docs/agents/company_setup.md.\n- Bundles the held API-keys grouped-by-owner UI change into this release.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.2.0: guided sector-aware company setup + Swiss pack",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T16:09:00Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4d8baa56d05530b5d07c598351195fba9c2cf8fc",
          "body": "Make the admin \"sees everyone's keys\" behavior legible on the API keys page\ninstead of a flat, ambiguous list:\n\n- Backend: list_api_keys LEFT JOINs \"User\" so each key carries owner_full_name\n  + owner_email, plus an is_mine flag. Additive only — no fields removed, safe\n  for a mixed-version window. \n[…]\nm (Badge, semantic tokens, ring-bordered lists,\n  Button variants) instead of ad-hoc gray utility classes.\n\nNo version bump yet (release held).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(api-keys): group keys by owner + confirm dialog for others' keys",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-15T13:39:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "36c87d753606316273351b7848cf6febb0e77c56",
          "body": "0.1.48's per-user keys named the column `user`, which is a reserved word\nin PostgreSQL — schema setup died with 'syntax error at or near \"user\"'\n(SQLite happily accepted it; the dual-backend CI suite caught it before\nany deploy). Renamed to `owner` in the DDL, migration 19, and every\nquery; the seri\n[…]\nield stays `user` so the frontend and API\nconsumers are unchanged. 0.1.48 was published but never deployable on\nPostgres — no data implications.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.49: rename Api Key column user -> owner (PG reserved word)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T17:30:59Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b43929a6293a4eb936a5ed33d086801cff8fb471",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: 0.1.48",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T17:28:28Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7a2c43c56a2ef74e982636c27cdca472acc35f74",
          "body": "v1 keys were org-global objects minted by admins with a free-standing\nrole and a synthetic identity (session_owner apikey:<id>) — whoever held\nthe token WAS the key, with no user attribution and, via a shared org\ntoken, interleaved chat sessions across people.\n\nv2 (clean break, decided 2026-07-14 — \n[…]\nd: same-user keys SHARE sessions (semantic flip), plus\n  cross-user isolation, cap enforcement, and the delete flow via a\n  second (viewer) user\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "auth: per-user API keys (self-service, live role cap, two-step delete)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T17:28:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "793d99792b285a2a766d3893d72917f782312f46",
          "body": "The 0.1.46 Master Data Deletion prompt section contained a literal\n{\"disabled\": 1} inside build_system_prompt's f-string — syntactically\nvalid (py_compile passes: \"disabled\" parses as an expression with \" 1\"\nas its format spec) but raising \"Space not allowed in string format\nspecifier\" on EVERY prom\n[…]\npush. Escaped to {{\"disabled\": 1}};\nverified by evaluating the extracted f-string (also proves no other\nunescaped braces exist in the template).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.47: fix chat prompt f-string (0.1.46 broke every chat turn)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T15:41:58Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "1655bfac3861bcf244462f3c7a1265ee8dc5affc",
          "body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: 0.1.46",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T15:36:19Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "780b58357ecf71304e728f2893b1b0be37eba95f",
          "body": "The master form pre-filled default_currency with a hardcoded \"USD\"\n(company form) or left it blank (customer/supplier) — so a hasty save\ngave a CHF shop USD customers. A dedicated effect now fills an untouched\ncurrency field with the company base currency once it loads, without\nwiping other fields t\n[…]\ner already typed. The backend create path\n(chat/API) already inherited the company currency for customer/supplier\n— this aligns the GUI with it.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(gui): new-master currency defaults to the company base currency",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T15:11:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fc3cb8352092a18fef026284eea7a5b8bbc87033",
          "body": "… USD)\n\nDoctypes without a per-document currency column (Stock Entry, ...) store\ntheir values in the company BASE currency, but three render paths fell\nback to a hardcoded \"USD\" when row/form data had no currency field —\nstamping $ on CHF numbers (display-only; stored values were correct):\n\n- docume\n[…]\n KPIs, table cells, and chart tooltips\n\nStandard report pages (trial balance, GL, aging, ...) already bound\nuseBaseCurrency and were unaffected.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(gui): stop stamping $ on base-currency values (Stock Entry showed…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T15:07:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fb33cf6fb4261311bff2243ad838c7360e6a91b7",
          "body": "The agent had no way to delete master records and, worse, justified the\ngap with an invented policy (\"records are retained for audit integrity\")\ngeneralized from the documents-lifecycle prompt rule — while the GUI's\nadmin delete route worked fine (live repro: CUST-007 refusal, manual GUI\ndeletion ne\n[…]\n now scopes \"no delete /\n  audit integrity\" explicitly to DOCUMENTS with a new Master Data\n  Deletion section describing the protected behavior.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chat: delete_master tool + scope the no-delete rule to documents",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T14:59:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ce9fa8a260e9cf4d70cbaf7b150c0135078f036f",
          "body": "The Account table always had full tree machinery (parent_account,\nis_group, root_type) but the GUI never exposed it — accounts were only\nvisible through Trial Balance / GL reports and the chat agent.\n\n- GET /reports/chart-of-accounts: every account (groups + zero-balance\n  included) with period bala\n[…]\nral Ledger pre-filtered to\n  account + period (the GL page is URL-backed, so drill-down is free).\n- i18n en/de/fr (Kontenplan / Plan comptable).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.45: Chart of Accounts page",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T14:29:51Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f9cc2e23ebfc077cbe9bb416c48d91218f98d0b4",
          "body": "…OM guidance\n\nStock UOM (and every other master-form select) silently rendered the\n\"Select...\" placeholder when the stored value wasn't in the hardcoded\noption list — which is every chat-created item (\"Stück\", \"Bottle\",\n\"Unit\"): the backend value existed but the GUI looked unset, inviting\nusers to o\n[…]\ns as users add units), nudging the agent\nto reuse exact spellings; create_master guidance points at it. A proper\nUOM master remains future work.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.44: show out-of-list select values in the GUI + dynamic U…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T13:40:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "4aa7aea161f5e9101f860b0848a775c69fab76dc",
          "body": "… versioning)\n\n- System prompt: sales-doc VAT contract — one \"On Net Total\" taxes[] row;\n  account_head OPTIONAL on drafts. The agent previously burned its step\n  budget hunting for a Tax Payable account that rate-only lines don't need\n  (live repro: 7/8 iterations, then refused; QTN-0004's working \n[…]\nw carries `modified` so callers can tell a\n  stale PDF from the current one (timestamped attachment names).\n- Hoist ORCHESTRATOR_MODEL constant.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.43: chat agent robustness (VAT guidance, cap wrap-up, doc…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T10:22:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "f91139e53f300b99467c0e867e9bb5f3e2c94a4d",
          "body": "Complete the terra pricing entry with the 5.6 family's cache-write rates\n(3.125 / 6.25 per 1M, short/long context). gpt-5.4 verified against the\nofficial tiering table (272K threshold).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.42: gpt-5.6-terra cache-write pricing",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T09:59:32Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "81969b40db46ed77b3d61ca5b978fbd8d26895d7",
          "body": "…nput)\n\nOfficial model page: requests exceeding 272K input tokens incur 2x input\nand 1.5x output charges — same structure as gpt-5.4. 0.1.39's flat entry\nunder-counted large-context calls.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.41: gpt-5.6-terra pricing is tiered (2x/1.5x above 272K i…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T09:55:56Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d8fdc0e360afa630bef36f263c955a1c62253eca",
          "body": "0.1.39's terra switch broke every chat turn: gpt-5.6-terra 400s on\n/v1/chat/completions when function tools are present unless\nreasoning_effort=\"none\" — and the loop swallows LLM errors into an\non_event, so it surfaced as silent empty replies. Set the param;\nResponses-API migration (reasoning + tools) is follow-up.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release 0.1.40: fix gpt-5.6-terra tool calls (reasoning_effort=none)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T09:52:49Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "001ba4f4ab0aea786e3e2c9c87b833ff9c874833",
          "body": "Carries the chat orchestrator switch gpt-5.4 -> gpt-5.6-terra (5b66e5b).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "release: 0.1.39",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T09:30:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5b66e5b21df4f9e94f20b3d27602204f4cc76db4",
          "body": "Register gpt-5.6-terra in OPENAI_PRICING (flat $2.50/$0.25/$15, no 272K tier\nstep-up) so cost tracking is accurate rather than falling back to gpt-5.4's\ntiered rate. Same price at normal context, stronger agentic tool-use.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "chat: switch orchestrator model gpt-5.4 -> gpt-5.6-terra",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-14T09:03:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cae9f1addcabdcca099375bbefe790aab9948aa2",
          "body": "Point readers to lambda-erp-example next to the PyPI/npm badges — a minimal\ndeployment that consumes both packages via version pins, a template to start from.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): link the reference deployment (lambda-erp-example)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-13T12:49:08Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5c2eee9869117ac1ece1f9f3eebec8d7131fe7c9",
          "body": "Remove the \"not yet production-ready … run your payroll\" disclaimer and soften\nthe remaining prototype language (tagline, storage row, Status section) to a\nconfident-but-honest tone. No functional change.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(readme): drop the not-production-ready framing",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-13T10:14:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "1f757918b713186752a9377c4cd480df85e8ebfb",
          "body": null,
          "is_bot": false,
          "headline": "Release v0.1.38",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-13T09:17:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cb069b2d0a8dc63907807ff39ee4ae70c0c5570c",
          "body": "The chat agent writes for its own web UI, so API-channel replies contained\nERP-relative links (/app, /masters, /api/documents) that are dead outside the\nERP. Fix in two layers:\n\n- run_session_turn takes a `channel` (\"web\" | \"api\"); the API surface passes\n  \"api\", switching the system prompt's link g\n[…]\ne-parsing prose.\n\nTests assert the api-channel prompt is applied and the documents array is\npopulated from a referenced PDF link. Docs updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(chat-api): channel-aware replies + structured document refs",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-13T09:13:34Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "fcc138ad69fed038e95602c37d943b56e4ed0f74",
          "body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Document read endpoints on the chat API + self-host Inter — 0.1.37",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-10T20:44:38Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "cca56dd40e64d921ed04a210ddc79d151cc57cc7",
          "body": "Chat replies link to /api/documents/{slug}/{name}/pdf, but that route is\ncookie-gated (require_role) and unreachable by a Bearer API caller — so PDFs a\nreply references can't be opened downstream (the iOS app / websocket).\n\nMirror them on the programmatic surface:\n- GET /api/v1/documents/{doctype_sl\n[…]\nerits the chat_api_enabled flag + key role). Missing\ndoc -> 404, unknown doctype -> 422 via the existing global handlers. Tests +\ndocs updated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "feat(chat-api): Bearer-gated document PDF + JSON read endpoints",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-10T20:40:41Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "b1332d09be4c4dd53177de1d7b56b79c2e6911ac",
          "body": "The package's Tailwind preset sets fontFamily.sans to [\"Inter\", ...], but Inter\nwas only loaded by the demo's Google Fonts <link> in index.html — which is not\npart of the published @lambda-development/erp-core package. Consumers (e.g.\nlambda-erp-internal) therefore asked for \"Inter\" but loaded nothi\n[…]\ntop of src/index.css, which ships via exports[\"./styles.css\"]. Every\nconsumer of the stylesheet now gets Inter self-hosted, no <link> required.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "fix(frontend): self-host Inter so consumers inherit the font",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-10T18:04:02Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "410c35c2f36abc6492b011977af2ecb2022c58f8",
          "body": "npm@latest shipped 12.0.0, whose global self-upgrade left 'sigstore'\nunresolved and crashed provenance generation, failing the 0.1.36 npm\npublish (PyPI succeeded). Pin npm@11 and make the PyPI step skip-existing\nso re-pointing the v0.1.36 tag completes the release without choking on\nthe already-published PyPI version.",
          "is_bot": false,
          "headline": "ci(release): pin npm to 11.x + skip-existing on PyPI",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-10T17:11:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "84ac63b8199c78f06956d4559eaf4f842b9051a5",
          "body": "Add a synchronous REST surface over the chat agent so an external application can\nconverse with an ERP instance (the basis for driving it from Lambda's own infra\nand, later, a mobile app). Off by default via the `chat_api_enabled` Settings\nflag; an admin enables it and issues Bearer API keys.\n\n- New\n[…]\ni18n en/de/fr.\n- Tests: tests/test_chat_api.py (gating/auth/keys/sessions/stateless-vs-replay),\n  wired into CI on SQLite + Postgres.\n- Docs: docs/chat-api.md (usage) + docs/chat-api-plan.md (design).",
          "is_bot": false,
          "headline": "Programmatic chat API — opt-in Bearer-key chat endpoint — 0.1.36",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-07-10T17:03:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "66ad0bc1cb905c022693166292ff54c69ddbe3fe",
          "body": "A user created via Google/Apple has no password. Settings now shows a \"Set a\nPassword\" card (no current-password field) so they can add an email+password\nfallback if they lose provider access.\n\n- New POST /auth/set-password (authenticated; refuses if a real password already\n  exists — use change-pas\n[…]\nnge Password so password users are\n  unaffected. Auth context gains refreshUser() to flip the card after setting.\n- i18n en/de/fr.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Set a password for social-login-only accounts — 0.1.35",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-07-01T17:57:25Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "00b7f18d621e3f71de5c7745cc908939320c5c5f",
          "body": "When registration is closed (not first-run, public signup off), the login page\nno longer shows the \"Register\" link that led to a dead-end signup form. Invite-\nonly instances now show sign-in only (password + configured social providers);\ninvited users still register via their invite link, completable with a password\nor by continuing with Google / Apple.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "No signup screen on invite-only instances — 0.1.34",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-07-01T16:47:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "2f0ee9266b1a4c839a4d960e6dfa4fc0e946f9c4",
          "body": "The \"User OAuth Identity\" table added in 0.1.32 had a column named `user`,\nwhich is a reserved word in PostgreSQL, so CREATE TABLE failed at startup on\nPostgres deployments (SQLite accepts it, so it passed local testing). Rename\nthe column to `user_name` and update all references. Verified against the\nPostgreSQL validation suite (books balance) and the OAuth flow on Postgres.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix social-login table crash on PostgreSQL (reserved word) — 0.1.33",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-07-01T16:20:03Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "dcc163d4ef703207d9ef98d3b71ef17e8a46b702",
          "body": "Add OAuth/OIDC social login layered on the existing password auth: once a\nprovider proves identity, the same lambda_erp_token JWT cookie is minted, so\neverything downstream is unchanged and password login keeps working.\n\n- api/oauth.py: /auth/{provider}/login + /auth/{provider}/callback for Google\n \n[…]\n (buttons hidden).\n- Also: read-only Notes / Terms now preserve line breaks (whitespace-pre-line).\n\nSee docs/social-login-plan.md.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Social login (Google & Apple) + read-only notes line-break fix — 0.1.32",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-07-01T16:09:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6bbbf3ccc306c1c769a53cbdb093e6d85543923c",
          "body": "A submitted (read-only) document showed the Notes / Terms text in a <p>, which\ncollapses newlines. Render textarea fields with whitespace-pre-line in the\nread-only path so multi-line notes keep their formatting, matching the editable\ntextarea and the PDF.\n\nNo version bump — rides the next release.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Preserve line breaks in read-only Notes / Terms",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-29T16:59:59Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d85d86be7c40da69e2b61b7b034650d31be5d5c1",
          "body": "… 0.1.31\n\n- `---` (3+ dashes) in the Notes / Terms markup renders a full-width thin\n  divider. Core emits a semantic `<div class=\"rm-hr\">`; templates style it\n  (light grey default; a branded template can match its own separators).\n  Documented in the chat system prompt and the formatting-help toolt\n[…]\nription -> posted invoices (Phase 0/1/2, scheduler via Container Apps\n  Job, manual + chat conversion). No code from the plan yet.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Notes markup: horizontal rule (---), + recurring-subscriptions plan —…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-25T13:36:33Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a98e5cec19c6037480563af18c9e84a84e22f29a",
          "body": "….1.30\n\n- Fix: the line-item search picker was clipped by the table's overflow-x-auto\n  scroller. It now renders in a body portal with fixed positioning and follows\n  the input on scroll/resize.\n- Docs: the chat system prompt now covers the quotation line `frequency`\n  field (and when to use it vs the cosmetic `>>` note), and states the\n  `>> left | amount` pipe rule explicitly.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Portal the link-field dropdown + document frequency/notes in chat — 0…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-24T15:35:48Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e0d7e9eb0ecdd9b28a6db58f6fbe4068a3be31d7",
          "body": "A quotation line carries a frequency: One-time (default) or a recurring\ncadence (Monthly/Quarterly/Half-Yearly/Yearly, matching the Subscription\nintervals). When an offer mixes one-time and recurring lines, the headline\ntotals AND tax rows reflect the one-time part only, and each recurring\ncadence i\n[…]\ncker on\nquotation line items, and a split_by_frequency helper that runs the shared\ntax engine per group (engine itself unchanged).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Billing frequency on quotation lines (recurring offers) — 0.1.29",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-24T15:12:18Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "542d8d1ec0996391bab6dfd0ac2c0fb9a2d82e19",
          "body": "The line-item table gains a Description column, so a quotation/order/invoice\nline can carry its own blurb (like a Proposal position). It defaults from\nthe Item master on save (blank falls back to the master, never wiping it);\na typed value overrides it for that document only. Backend already stored\nand defaulted the field — this exposes it in the form.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Editable per-line description on document line items — 0.1.28",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-24T14:14:21Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4f7151b1bbfc966eac66f8548eaf9bb1fb19ce71",
          "body": "The remarks field moves onto its own full-width row below the other\ndocument fields and is taller, with an info icon beside the label that\nexplains the supported markup (# heading, *italic*/**bold**, and the\nright-aligned `>> Period | Amount` price line) on hover or click.\nTranslated for en/de/fr.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Make the Notes / Terms field prominent + markup help — 0.1.27",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-24T09:33:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "124879fc8262c719331aee4fc04ad274956da91f",
          "body": "The remarks field now renders on the PDF from a small markup subset\n(# headings, *italic*/**bold**, and a right-aligned `>> Period | Amount`\nprice line that sits beside the description above it), so a closing block\nreads like a real offer. generate_pdf exposes it as safe `remarks_html`;\ntemplates re\n[…]\nses, so a\nbranded template can restyle the same markup. The chat assistant knows\nthe syntax and uses it for customer-facing notes.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Lightweight markup for document Notes / Terms — 0.1.26",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-24T08:57:06Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "da8b2a9c5cfeb9ce9b8eb8e0dc9aa09d31a76fc5",
          "body": "When unsure where a value belongs on a master, the assistant now consults\nget_master_fields before create_master/update_master (tool + system-prompt\nguidance; the ignored-fields warning points there too). create_master also\nspells out the customer contact-person mapping with an example. Fixes contact\npersons being dropped / contact phones misfiled into the company phone.\n\nNo version bump — rides the next release.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Chat: discover master fields instead of guessing",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-06-23T22:06:58Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7f1638f84338bd44a640271681cbf0993041f795",
          "body": "Master search: case-insensitive matching (fixes a Postgres-only bug where\nsearch returned nothing unless the exact stored casing was typed), searches all\ntext columns incl. address/city, fuzzy-matches misspellings, with an optional\n`fields` arg to target columns and a new get_master_fields tool.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Bump to lambda-erp 0.1.25",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-06-23T21:30:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "5979ac8c1d16608eb7e5d88d993819ef90ac542b",
          "body": "…ix, addressing your three follow-ups.\n\n  1. Per-column targeting (fields)\n\n  search_masters now accepts an optional fields list. When provided it searches only those columns (validated against the\n  real schema; unknown names → clear error). It uses lower(CAST(col AS TEXT)) so even non-text columns\n[…]\nty + ERP validation suites pass locally on SQLite; the Postgres leg (where the original case bug lived) runs in\n  CI.\n\n  Still unpushed — say the word and I'll branch and open a PR against lambda-erp.",
          "is_bot": false,
          "headline": "All green on both suites. Here's what I added on top of the earlier f…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-06-23T21:10:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eb3ad3a69f69f02cbfcbc7fb20ccd7ad7bd4819e",
          "body": "The custom Proposal page had no way to remove a proposal. Add a Discard button\n(existing proposals only, with a confirm) that soft-deletes via the standard\ndiscard_document path (status Discarded, hidden from the list).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add Discard action to the Proposal builder — 0.1.24",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-22T07:46:26Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "bd232036f78cb87fc24822a0c78db3b609bab6cb",
          "body": "…— 0.1.23\n\nThe 0.1.22 Proposal guidance embedded a `{...}` JSON example in build_system_prompt's\nf-string, so the braces were treated as format fields and every chat message\nraised \"Invalid format specifier\". Rephrase the example as brace-free prose and\nadd the German doctype names (Sammelofferte/Sammelofferten) so the assistant\nmaps them to proposals.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Fix chat crash: literal braces in the Proposal system-prompt section …",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-20T17:24:06Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "42126b26cfe61943bf4c9900fd88a7c06bef461a",
          "body": "Add `proposal` to the LLM document tools (create/read/update/list) and\ndocument its shape in the system prompt: the quotations[] child table\nreferences existing quotations (not items), and it is print-only. Guard the\nProposal class against submit so an accidental submit raises a clear error.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Expose Proposal (Sammelofferte) to the chat assistant — 0.1.22",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-20T17:11:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f85da195b332033875029c5b0d851659f594d660",
          "body": "A print-only document that assembles several independent quotations into one\nbranded PDF: each rendered as a lettered position (A, B, C…) with an optional\nrecommendation badge, a cover letter pre-filled from a per-company template,\nand an optional uploaded appendix PDF stapled on the end (pypdf). No\n[…]\nthe nav. Tables Proposal / Proposal Item / Proposal Appendix\n(appendix as a blob); Company.proposal_cover_template (migration 17).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add Proposal (Sammelofferte) — combine quotations into one PDF — 0.1.21",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-20T16:18:15Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "3ff8f3fc0b041a435cc91c31007b4515291917bf",
          "body": "The Customer master gains contact_person / contact_email / contact_phone\n(a named contact at the customer, distinct from the company-level\nemail/phone). Surfaced in the master form with en/de/fr labels and in the\nchat create_master/update_master tools. Additive migration 16; existing\ncustomers keep the fields empty until edited.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add contact person (Ansprechperson) to Customer master — 0.1.20",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-19T11:47:55Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7950677ceba3084adf6d04d60ec906bc4efc5033",
          "body": "A microphone button in the chat composer records a spoken message,\ntranscribes it with OpenAI gpt-4o-transcribe, and drops the text into the\ninput for review before sending (it does not auto-send). Click to start,\nclick to stop; a too-short accidental tap is ignored without an API call.\n\n- api/chat.\n[…]\n_of_transcription().\n- frontend: mic button + MediaRecorder capture in the composer, transcribeAudio\n  on the chat context, and de/en/fr labels.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.19: voice-to-text in chat",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-17T17:52:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "6c63ecd736e773a5c725c73286958203abeba48f",
          "body": "Added — Discard draft:\n- Document.discard() soft-deletes an unwanted DRAFT (discarded=1, status\n  'Discarded'): keeps the row for the audit trail, hides it from default lists,\n  no GL/stock impact. Drafts only; submitted docs must be cancelled. submit()\n  refuses a discarded draft (no \"posted but hi\n[…]\ninline confirmation\n(confirm button placed apart from the original) so a double-click can't fire an\nirreversible posting reversal.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.18: discard draft (void) + two-step cancel confirmation",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-05T11:09:24Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "a423566e54ba2c4a000b6cf6640174e6ad8c24d9",
          "body": "…tings UI\n\nFixed:\n- Change Password form now works with password managers: autocomplete\n  current-password / new-password (on both new + confirm so managers fill the\n  generated password into both), unique id/name per field, and a hidden\n  username anchor (autocomplete=username, display:none) so 1Pa\n[…]\nnding-invite \"Copy link\" / \"Revoke\" are now proper Buttons\n  (secondary / danger) instead of text links, matching \"Create Invite\".\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.17: password-manager-friendly change-password form + set…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-05T08:50:28Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "47e1be2c6ae2fa7922b8ff053599e4e7cd45f693",
          "body": "Signed-in users can change their own password from General Settings (a card\nreachable by every role; hidden for the shared public_manager demo account).\n\nNew endpoint POST /auth/change-password verifies the current password, requires\nthe new one to be >= 6 chars, and rejects public_manager. Wrong current -> 403,\ntoo short -> 422. Auth-flow regression (both backends) extended to cover it.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.16: change password",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-05T08:32:39Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "613ae2885586aa916ec5f2972b38a6e2b0029a13",
          "body": ".lambda-logo-icon masked its gradient with url('/logo_lad_erp.png') — an\nabsolute path to an asset only in the core's own public/ and not shipped in the\nnpm package, so every downstream deployment (e.g. acme-erp, lambda-erp-internal)\nrendered a broken/empty logo. Move the mark to src/logo_lad_erp.pn\n[…]\ne files. The Paint.NET source moves to frontend/design/ so it stops\nshipping in builds. Frontend only; backend bumps for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.15 (fix sidebar logo for consumer deployments)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T22:40:31Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "8d7535085e74fdec503105f17a1afde10096a7b7",
          "body": "… fix\n\nAdded:\n- Opt-in public signup. New admin setting `allow_public_signup` (default off)\n  under General Settings; when on, anyone may self-register as a viewer. First\n  user still bootstraps as admin; toggle off keeps registration invite-only.\n  setup-status now returns first_run / public_signup\n[…]\n admin-only, leads with total LLM spend off-demo.\n- Double-quoted-literal CI guard now scans continuation lines of multi-line SQL.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.14: opt-in public signup, invite management, Token Spend…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T18:08:05Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "218a0a89d2a359635864246279f0223d2d220925",
          "body": "Two generic mechanisms a deployment plugin needs to render a payment slip\n(e.g. a Swiss QR-bill) without forking the core:\n\n- register_pdf_context(fn): providers fn(doctype, name, context) return extra\n  keys merged into the PDF render context just before rendering. Exceptions in\n  a provider are sw\n[…]\nn field (schema + migration _m014) and an IBAN input on the\n  company master form. generate_pdf now includes iban in company_info.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.13: register_pdf_context seam + Company.iban",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T17:00:39Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "12afba01448497e515ea90213cbd85260f266150",
          "body": "…url)\n\ngenerate_pdf sets WeasyPrint base_url to the rendered template's directory, so\na register_pdf_template_dir override can `<img src=\"logo.png\">` a logo (or load\nfonts/CSS) sitting next to its document.html.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.12 (PDF templates can reference sibling assets via base_…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T13:12:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "9d80c0f4c5cf72186a8fbb05caf7bf5d4e4e63cd",
          "body": "- register_pdf_template_dir: deployments can override the invoice/document PDF\n  template with their own styling.\n- New customers/suppliers inherit the company's base currency instead of\n  defaulting to USD (fixes non-USD companies getting USD-defaulted documents);\n  Currency field exposed on the master forms.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.11 (PDF template seam + party currency inheritance)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T12:33:44Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "7d48aee25f7e4ac0f46bb0d406f3f51d443509ee",
          "body": "Deployment plugins can register a template directory whose document.html (and\nother templates) override the built-in invoice/document PDF, searched before\nthe core's via a Jinja ChoiceLoader. Custom templates get the same render\ncontext generate_pdf() builds, so they only restyle the same data. No change\nwhen nothing is registered.\n\nNo release cut (per request); lands on master in [Unreleased].\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Add PDF template override seam (register_pdf_template_dir)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T12:28:34Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "16a00976167701278c4d1c4c0f15ada3f206c53c",
          "body": "New customers/suppliers defaulted to USD (the default_currency column default),\nso a non-USD company (e.g. CHF) got USD customers that forced sales/purchase\ndocuments to USD and failed with no USD->base rate. create_master_record now\nfills default_currency from the company when not provided (explici\n[…]\n it\nwas only settable via the API/chat, hence invisible in the UI.\n\nNo release cut (per request); lands on master in [Unreleased].\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Party masters inherit company currency; expose Currency on the form",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T12:18:29Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "0d238d71cfb10a5d552480784ea85b4527491db7",
          "body": "The v0.1.10 release failed because pypa/gh-action-pypi-publish is a Docker\naction whose image is pulled from ghcr.io, and the anonymous pull returned\n\"docker: ... unauthorized\" (ghcr anonymous-pull rate limit / flake) — the\npublish never reached PyPI. Log in with GITHUB_TOKEN first so it's an\nauthenticated pull. Adds packages: read.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "ci(release): authenticate to ghcr.io before the PyPI publish step",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T09:42:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "502d41f375b9642e44d721bb01556c69f6616909",
          "body": "…fill)\n\n/setup/company used to fill missing contact fields with a deterministic\npseudo-random US address (for complete-looking demo PDFs) — so every real\ncompany got a bogus address on its invoices. The setup form now collects\naddress/city/zip/country/tax-id/email/phone (optional), and the backend only\nauto-fills when the caller passes autofill_address (the demo seeding does).\nReal setups keep unprovided fields blank.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.10 (Company Setup: collect real address, stop fake auto-…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T08:44:29Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "f0501f137840b7798dbb2a37eeec23b36b28bb16",
          "body": "A NavLink to a path that's a prefix of a sibling's (/setup \"Company Setup\" vs\n/setup/opening-balances \"Opening Balances\") matched active on the longer path's\npage, so both rows showed the active grey background on the Opening Balances\npage. Items nested under a sibling now use exact (end) matching. Frontend-only;\n0.1.9 for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.9 (sidebar: stop double-highlighting nested nav paths)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-04T07:56:25Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "703018c0363f7bf89b48c2a265dfb8716627cbea",
          "body": "…mplete)\n\nFrontend-only changes; backend bumps for version lockstep.\n\n- Setup page gains a \"Create empty company, no demo data\" seed mode that creates\n  only the company + chart of accounts and seeds nothing.\n- Sidebar hides the \"Company Setup\" (/setup) link once a company exists.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.8 (Company Setup: no-data option + hide nav link once co…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T22:30:17Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "e50b3695b25a5494d045a8a5dce9ce593231eb84",
          "body": "Two frontend-only changes to the Company Setup flow, both for all deployments:\n\n- setup page gains a third seed mode, \"Create empty company, no demo data\",\n  that creates only the company + chart of accounts and seeds nothing (for real\n  deployments starting from scratch). Backend already exposed co\n[…]\nxisting setup-status\n  query invalidation makes the link vanish reactively. Getting Started and\n  Opening Balances are unaffected.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Setup: add no-data option + hide Company Setup nav link once complete",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T22:29:16Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "9bceb63a7dfd63d9680672e9fdbeb3bb40780ec8",
          "body": "db.sql() always called fetchall(); after INSERT/UPDATE/DELETE psycopg raises\n\"the last operation didn't produce records\" (SQLite returns []). This broke the\nchat/WebSocket path (constant disconnect/reconnect) and other db.sql write call\nsites. Now fetches only when cursor.description is not None. test_db_portability\nextended to assert write-via-db.sql() returns [] on both backends. Frontend\nunchanged; 0.1.7 for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.7 (db.sql() no longer raises on Postgres for writes)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T17:50:07Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "d71064d07e881c4816d1ac7200958e2c59d656d3",
          "body": "…esilience)\n\nDouble-quoted string literals in SQL (WHERE x = \"value\", IN (\"a\",\"b\")) broke on\nPostgres — it reads \"...\" as an identifier, not a string — 500ing auth/chat/pdf\n/master paths. Converted all to single-quoted values. Also: a failed statement\nunder autocommit=False left the thread-local con\n[…]\ny (static double-quote scan + functional auth\nsmoke test on both backends), wired into CI. Frontend unchanged; 0.1.6 for lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.6 (fix double-quoted SQL literals; Postgres connection r…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T17:32:50Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "24ef54e0572c541f11fe621927a7e8b83d00fd1a",
          "body": "gotchas.md gains the dual-backend portability rules (portable SQL, the\ntransaction-abort and quoted-identifier differences); decisions.md updates the\nSQLite-vs-Postgres entry to reflect optional Postgres (added because Azure SMB\ncan't host SQLite's file locks).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs(agents): note dual SQLite/Postgres backend",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T16:54:41Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "4e3895c8b0ab2c31617a670c0461f649588f58d9",
          "body": "Add a Postgres backend to lambda_erp/database.py alongside SQLite (still the\ndefault). Select it at runtime via LAMBDA_ERP_DB=postgresql://...; install the\ndriver with the new lambda-erp[postgres] extra. A _PgConn wrapper (?->%s) and\n_PgRow (mirrors sqlite3.Row) keep the ~35 internal + external db.c\n[…]\nn SQLite AND a Postgres service container;\nboth produce identical balanced books. Frontend unchanged; ships at 0.1.5 for\nlockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.5 (optional PostgreSQL backend)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T16:32:10Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "ed2e388ef47b30eac5c213f1bb44823f0795c1d4",
          "body": "…yments)\n\nWAL needs a memory-mapped -shm file, so `PRAGMA journal_mode=WAL` fails with\n\"database is locked\" when the SQLite DB lives on an SMB/NFS share (e.g. Azure\nFiles). Add LAMBDA_ERP_SQLITE_JOURNAL_MODE (default WAL, allowlist-validated);\na network-FS deployment sets it to DELETE. Frontend unchanged; ships at 0.1.4\nto keep the packages in lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.4 (configurable SQLite journal mode for network-FS deplo…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T15:21:11Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "806e1abe145b2acdbc93632960cde5d73fa33d26",
          "body": "Add version badges for lambda-erp (PyPI) and @lambda-development/erp-core\n(npm) to the top badge cluster — standard for published packages and the\nlinks were missing.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "docs: link PyPI + npm package pages from README",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T14:54:57Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "6c258904bac97f68544444e83b9d42fa1110ba12",
          "body": "…buildable)\n\nerp-core@0.1.2 emitted an absolute /assets/report-runtime.worker-*.js URL\nfrom `new Worker(new URL(...))`, which a downstream Vite build resolved\nagainst its own public/ dir and failed on (\"Could not resolve entry\nmodule\"). Import the worker with ?worker&inline so it's embedded as a blo\n[…]\nindex.js — nothing external for consumers to resolve. Backend\nunchanged; ships at 0.1.3 only to keep the two packages in lockstep.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Release v0.1.3 (fix: inline analytics worker so erp-core is consumer-…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-03T14:45:57Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "d3acdc5e375360ef86b55001c9921c4beb319999",
          "body": null,
          "is_bot": false,
          "headline": "some updates to readmes",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-06-02T14:00:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7ee15a557616e0633273a2f090f86a33cbcb1138",
          "body": "  - Backend lambda-erp and frontend @lambda-development/erp-core are both published and live on PyPI + npm at 0.1.2, via a keyless OIDC tag-triggered pipeline (release.yml) that also auto-creates the GitHub Release from the changelog.\n  - The doc now records Phase C as DONE with the three hard-won l\n[…]\nt README-only (it doesn't prove the packages compose), and a separate project (rather than an examples/ dir, which tends to drift to workspace deps and clutter the monorepo) — which is what you chose.",
          "is_bot": false,
          "headline": "What's done (Phases A → C)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T22:22:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dc7cda947f1031085fd1179c181831f46b77a9d5",
          "body": "  - actions/checkout@v4 → @v5 (×4)\n  - actions/setup-python@v5 → @v6\n  - actions/setup-node@v4 → @v6\n\n  (pypa/gh-action-pypi-publish@release/v1 isn't in the list because it's a Docker-based action, not a Node one — it doesn't trigger this warning.)\n\n  These take effect on the next release run, since\n[…]\n bump it to checkout@v5 too if you want to clear that warning as well. Want me to?\n\n  Sources:\n  - Deprecation of Node 20 on GitHub Actions runners\n  - actions/setup-node (v6)\n  - actions/setup-python",
          "is_bot": false,
          "headline": "Done — release.yml updated and YAML re-validated:",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T21:51:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9283e56386bb7120a27b83b61446d3b1bf8b5856",
          "body": null,
          "is_bot": false,
          "headline": "Release v0.1.2 (fix npm provenance: add repository to package.json)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T21:47:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "60a3c6c0e6b3887c246ab2f82b9af3ffc677b286",
          "body": null,
          "is_bot": false,
          "headline": "Release v0.1.1",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T21:41:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "098d9051d8cebbafc040d85e2657c02ad5fb13e7",
          "body": "…e packaging plan.",
          "is_bot": false,
          "headline": "Done — docs/releasing.md is the runbook, with a pointer added from th…",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T21:31:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1468730436fa4242ad6b9770b3e5458e64ee1ac6",
          "body": "  1. CHANGELOG.md (root) — Keep-a-Changelog + SemVer, one unified log for both packages, seeded with the 0.1.0 entry (core engine, multi-currency, stock analytics, i18n, open-core packaging) and an empty [Unreleased] to accrue into. Notes that the\n  extension seams are the semver-governed surface.\n \n[…]\nrs the Azure deploy (code changes), so tell me whether to commit + push or just commit and hold —\n  and then the first keyless release is: bump both to 0.1.1, git tag v0.1.1 && git push origin v0.1.1.",
          "is_bot": false,
          "headline": "  What I added",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T21:25:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "19fb1af25272357e9a5d2cbf809343a23d9a3ff9",
          "body": "  What I just did\n\n  .github/workflows/release.yml (new) — tag-v*-triggered (+ manual dispatch), fully keyless OIDC:\n  - verify-version — fails the release unless tag (minus v) == pyproject version == frontend/package.json version. Dry-ran the extraction: both read 0.1.0. ✓\n  - publish-pypi — python\n[…]\necisions (OIDC, release env, private flipped) and the remaining manual checklist.\n\n  Validated: release.yml parses as YAML, package.json is valid JSON with private gone, version-lockstep check passes.",
          "is_bot": false,
          "headline": " Phase C's code is in place and validated.",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T20:50:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0a111ae896f08ce1e6492722202238f49be5d999",
          "body": "… re-verified.\n\n  What I changed and confirmed:\n  - Renamed @lambda/erp-core → @lambda-development/erp-core across frontend/package.json, src/index.ts, vite.lib.config.ts, tailwind.preset.ts, the README customer-deployment section, and both planning docs. No\n  stale references remain.\n  - Regenerate\n[…]\n and the trusted-publisher settings to paste into each\n  registry.\n  - Sequencing footer marks 1–3 done, Phase C next. Also synced docs/core-extension-architecture.md and the README to the final name.",
          "is_bot": false,
          "headline": "Done — the package is now @lambda-development/erp-core everywhere and…",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T18:12:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b52908c28e90248d0f4f7be0c1a8f0a98e1e4a6f",
          "body": "  Frontend override seams (additive — demo app unchanged, builds green):\n  - Doctype registry — registerDoctype on the existing lib/doctypes.ts (pages already read it live).\n  - Route registry — routes.tsx now exposes registerRoute + buildRoutes() with merge-by-path, so a registered route overrides \n[…]\nk → a scratch consumer app installed the tarball + peers and tsc --noEmit passed while\n  exercising every seam. Docker's npm ci stays valid (lockfile regenerated). README + both planning docs updated.",
          "is_bot": false,
          "headline": "Phase B is done and verified. Here's what landed.",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T17:46:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e00e5cdabc43d676a10be799d7678053b8f3108d",
          "body": "  pyproject.toml\n  - Build backend flit → hatchling. flit packages only the one module matching the project name, so it was silently dropping api — the wheel would've installed without register_doctype / load_plugins / the\n  document classes. Now: packages = [\"lambda_erp\", \"api\"].\n  - Added readme, \n[…]\np venv (kept dist/).\n\n  One nice side effect: a future pip install -e . now makes api importable via the editable install itself, instead of only working because you launch uvicorn from the repo root.",
          "is_bot": false,
          "headline": "Phase A is done. Here's what changed and how it was verified.",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T17:16:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0caf64e1d8751e68be5a2da434d1992ff8869975",
          "body": "  Added \"Building a customer deployment on top of the core\" to README.md (after \"Repository layout\"). It tells a future dev/LLM how to: stand up a separate private repo that depends on the core, override logic\n  (subclass + register_doctype), add behavior (register_hook, with the before-=in-txn / af\n[…]\nis a no-op.\n  Env + injected modules + hooks are restored in finally.\n\n  So the whole extension seam — registry, hooks, converters, and the loader — is now regression-protected in the canonical suite.",
          "is_bot": false,
          "headline": "README",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T16:29:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "862dd8e0a8cf336e82ef49ca59ba6626aed4772a",
          "body": "  - register_converter(source, target, fn) — lets a plugin replace conversion logic for a (source, target) pair.\n  - convert_document now honors class overrides generically: after the core converter builds the (base-class) target doc, if a subclass is registered for that doctype, it upgrades the ins\n[…]\n hook lifecycle events, swap converter logic, and is loaded via LAMBDA_ERP_PLUGINS — all without editing\n  core files, all additive (zero impact when no plugin is set), and all exercised by the suite.",
          "is_bot": false,
          "headline": "What landed (api/services.py)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T16:20:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eda874862a40703089da8aa10ed0422e27795416",
          "body": "  api/main.py — new load_plugins(), called in the lifespan right after setup() (so overrides/hooks are registered before anything — including demo seeding — creates documents):\n  - Reads LAMBDA_ERP_PLUGINS (comma-separated module names), imports each, and calls its register().\n  - Fails fast if a na\n[…]\n(registered a hook + doctype path).\n  - A module without register() raises a clear RuntimeError.\n  - Empty LAMBDA_ERP_PLUGINS is a clean no-op.\n  - api.main imports fine; full validation suite passes.",
          "is_bot": false,
          "headline": "  What landed",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T16:15:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bc27cb37315d6433117804c9283ee6dc6b69d2d1",
          "body": "  Phase 1 — registry seam (api/services.py)\n  - Added register_doctype(doctype, cls, slug=None) over the existing DOCUMENT_CLASSES dict. Since get_document_class already resolves live, all of create/load/update/submit/cancel_document honor an override\n  automatically — no other change needed.\n\n  Pha\n[…]\nnd zero-impact by default: with no plugins registered, run_hooks is an empty dict lookup and the registry holds the core classes, so existing behavior is byte-identical (the full suite\n  confirms it).",
          "is_bot": false,
          "headline": " What landed",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T16:02:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1de26ea5ac8cbdd01f48ebddaa7939ed88208033",
          "body": "  - 167 label keys (fields.*, conversions.*, tables.*, tutorial.chips.*, tutorial.links.*) — the key suffix is the English label (and matched the inline defaultValue), so derived directly.\n  - 40 step strings (tutorial.steps.N.{title,description,tip}) — recovered from the STEPS array that's still in\n[…]\ns at all), I can remove them as a follow-up; otherwise they're a safe belt-and-suspenders.\n\n  en.json, de.json, and fr.json are now structurally identical, so future missing-key drift is easy to spot.",
          "is_bot": false,
          "headline": " What I moved into en.json (244 keys)",
          "author_name": "Jonathan",
          "author_login": "jcfrei",
          "committed_at": "2026-05-26T10:51:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "15b3f81cf134424982caa684b9994f70670ea15c",
          "body": "  Dashboard — the four metric cards (Total Revenue, Outstanding Receivable/Payable, Total Stock Value), the \"Recent Documents\" heading, the empty state, and each recent-doc's doctype label.\n\n  Chat — empty-state title + subtitle, the four suggestion chips, \"Load older messages\", attachment statuses \n[…]\ner your call. Everything's been verified green — want me to commit the whole i18n effort now (engine + reports + forms + lists + dashboard + chat + tutorial)? If so I'll\n  group it into clean commits.",
          "is_bot": false,
          "headline": "What's now translated (en/de/fr)",
          "author_name": "Jon",
          "author_login": "jcfrei",
          "committed_at": "2026-05-25T22:15:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 60,
      "commits_last_year": 148,
      "latest_release_at": "2026-07-17T13:24:50Z",
      "latest_release_tag": "v0.3.4",
      "releases_from_tags": false,
      "days_since_last_push": 2,
      "active_weeks_last_year": 11,
      "days_since_latest_release": 5,
      "mean_days_between_releases": 0.2
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 50,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "lambda-erp",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "pypi",
          "matches_repo": null,
          "registry_url": "https://pypi.org/project/lambda-erp/",
          "is_deprecated": false,
          "latest_version": "0.3.4",
          "repository_url": null,
          "versions_count": 63,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 4886,
          "first_published_at": "2026-05-26T21:37:29.460244Z",
          "latest_published_at": "2026-07-17T13:24:31.340288Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        },
        {
          "name": "@lambda-development/erp-core",
          "exists": true,
          "license": "Apache-2.0",
          "keywords": [],
          "ecosystem": "npm",
          "matches_repo": true,
          "registry_url": "https://www.npmjs.com/package/@lambda-development/erp-core",
          "is_deprecated": false,
          "latest_version": "0.3.4",
          "repository_url": "https://github.com/lambdadevelopment/lambda-erp",
          "versions_count": 61,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": 1,
          "monthly_downloads": 6160,
          "first_published_at": "2026-05-26T21:12:41.847000Z",
          "latest_published_at": "2026-07-17T13:24:40.890000Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 5
        }
      ]
    },
    "popularity": {
      "forks": 5,
      "stars": 20,
      "watchers": 0,
      "fork_history": {
        "days": [
          {
            "date": "2026-05-26",
            "count": 1
          },
          {
            "date": "2026-06-17",
            "count": 2
          },
          {
            "date": "2026-06-28",
            "count": 1
          },
          {
            "date": "2026-07-14",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 5,
        "total_forks": 5
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": true,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [
        "frontend/tsconfig.json"
      ],
      "toolchain_manifests": [],
      "largest_source_bytes": 181453,
      "source_files_sampled": 145,
      "oversized_source_files": 3,
      "agent_instruction_files": [
        "CLAUDE.md"
      ],
      "agent_instruction_max_bytes": 1598
    },
    "dependencies": {
      "manifests": [
        "frontend/package.json",
        "pyproject.toml"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "npm",
        "pypi"
      ],
      "dependencies": [
        {
          "name": "@fontsource/inter",
          "manifest": "frontend/package.json",
          "ecosystem": "npm",
          "version_constraint": "^5.2.8"
        },
        {
          "name": "fastapi",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.115"
        },
        {
          "name": "uvicorn",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.30"
        },
        {
          "name": "python-multipart",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.0.9"
        },
        {
          "name": "pydantic",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.0"
        },
        {
          "name": "anthropic",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.40"
        },
        {
          "name": "openai",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.0"
        },
        {
          "name": "httpx",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.27"
        },
        {
          "name": "python-dotenv",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.0"
        },
        {
          "name": "python-dateutil",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=2.8"
        },
        {
          "name": "python-jose",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3.3"
        },
        {
          "name": "bcrypt",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=5"
        },
        {
          "name": "Jinja2",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3.1"
        },
        {
          "name": "weasyprint",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=62.0"
        },
        {
          "name": "pypdf",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=4.0"
        },
        {
          "name": "holidays",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.40"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "jcfrei",
          "commits": 148,
          "avatar_url": "https://avatars.githubusercontent.com/u/523261?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "deploy.yml",
        "release.yml",
        "terraform-apply.yml"
      ],
      "has_docs_dir": true,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "package-lock.json"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 3,
            "reason": "project has 1 contributing companies or organizations -- score normalized to 3",
            "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": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 1,
            "reason": "dependency not pinned by hash detected -- score normalized to 1",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 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": 0,
            "reason": "11 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "39068a6e52f556509734450d296da9a3e65cc4a2",
        "ran_at": "2026-07-22T15:11:10Z",
        "aggregate_score": 3.6,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/lambdadevelopment/lambda-erp",
    "host": "github.com",
    "name": "lambda-erp",
    "owner": "lambdadevelopment"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 53,
      "inputs": {
        "security": 36,
        "vitality": 83,
        "community": 45,
        "governance": 34,
        "engineering": 66
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 83,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "good",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "commits_last_year": 148,
              "human_commit_share": 1,
              "days_since_last_push": 2,
              "active_weeks_last_year": 11
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 2 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 2
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "11/52 weeks with commits",
                "points": 7.6,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 11
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "148 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 148
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 60,
              "latest_release_tag": "v0.3.4",
              "releases_from_tags": false,
              "days_since_latest_release": 5,
              "mean_days_between_releases": 0.2
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "60 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 60
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~0.2 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 0.2
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 45,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 26,
            "inputs": {
              "forks": 5,
              "stars": 20,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "20 stars",
                "points": 20.7,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 20
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "5 forks",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (Apache-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "Apache-2.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
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 67,
            "inputs": {
              "packages": [
                "lambda-erp",
                "@lambda-development/erp-core"
              ],
              "dependents": null,
              "ecosystems": "npm, pypi",
              "total_downloads": null,
              "monthly_downloads": 11046
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "11,046 downloads/month across npm, pypi",
                "points": 53.9,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 11046,
                      "ecosystems": "npm, pypi"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 34,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 13,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution",
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "at_risk",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 41,
            "inputs": {
              "followers": 1,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "lambdadevelopment",
              "public_repos": 3,
              "account_age_days": 742
            },
            "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": "1 followers of lambdadevelopment",
                "points": 2.2,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 1,
                      "login": "lambdadevelopment"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "3 public repos, account ~2 yr old",
                "points": 8.4,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 3
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 2
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "lambda-erp",
                "@lambda-development/erp-core"
              ],
              "ecosystems": "npm, pypi",
              "any_deprecated": false,
              "min_days_since_publish": 5
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "2 package(s) on npm, pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 2,
                      "ecosystems": "npm, pypi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 5 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "63 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 63
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 66,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "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": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": true,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 36,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 36,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 3.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 not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 1 contributing companies or organizations -- score normalized to 3",
                "points": 0.8,
                "status": "partial",
                "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": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 1",
                "points": 0.5,
                "status": "partial",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "11 existing vulnerabilities detected",
                "points": 0,
                "status": "missed",
                "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": 1
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "good",
        "name": "AI Readiness",
        "value": 70,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "excellent",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.92,
              "agent_instruction_files": [
                "CLAUDE.md"
              ],
              "agent_instruction_max_bytes": 1598
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "CLAUDE.md",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "CLAUDE.md"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "92 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 92,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 54,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "package-lock.json"
              ],
              "has_dockerfile": true,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [
                "frontend/tsconfig.json"
              ],
              "agent_commit_share": 0.78,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "frontend/tsconfig.json",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "frontend/tsconfig.json"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "Dockerfile, lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "Dockerfile, lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "78 of the last 100 commits agent-authored or agent-credited",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 78,
                      "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 1",
                "points": 1,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "good",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 81,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 181453,
              "source_files_sampled": 145,
              "oversized_source_files": 3
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python with type-check config (frontend/tsconfig.json)",
                "points": 27,
                "status": "partial",
                "details": [
                  {
                    "code": "typecheck_config_language",
                    "params": {
                      "files": "frontend/tsconfig.json",
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "3/145 source files over 60KB",
                "points": 53.9,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 145,
                      "oversized": 3
                    }
                  }
                ],
                "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",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index pypi:lambda-erp@0.3.4; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-22T15:11:17.963013Z",
  "schema_version": "0.26.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/l/lambdadevelopment/lambda-erp.svg",
  "full_name": "lambdadevelopment/lambda-erp",
  "license_state": "standard",
  "license_spdx": "Apache-2.0"
}

Оцінки — це сигнали, а не гарантії. Вони відображають публічно видимі практики на GitHub — це не аудит коду й не гарантія безпеки.

Відсутні дані виключаються, а ваги перенормовуються — нуль за відсутність ніколи не ставиться. Методологія версіонована й відкрита: метрики v1.13.0, схема v0.26.0 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистикаPyPI, npm.