Informe JSON sin procesar legible por máquina
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 2046,
"has_wiki": true,
"homepage": null,
"languages": {
"HTML": 7979,
"Shell": 2646,
"Python": 1938307,
"Makefile": 320,
"JavaScript": 40115
},
"pushed_at": "2026-07-25T20:17:13Z",
"created_at": "2026-06-23T23:54:25Z",
"owner_type": "Organization",
"updated_at": "2026-07-25T20:17:13Z",
"description": "Core Django utilities for the Stapel framework — JWT, permissions, error handling, bus abstractions",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "Python",
"significant_languages": [
"Python"
]
},
"owner": {
"blog": null,
"name": null,
"type": "Organization",
"login": "usestapel",
"company": null,
"location": null,
"followers": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/296323797?v=4",
"created_at": "2026-06-23T23:51:53Z",
"is_verified": null,
"public_repos": 31,
"account_age_days": 31
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.14.2",
"kind": "patch",
"published_at": "2026-07-25T20:17:05Z"
},
{
"tag": "v0.14.1",
"kind": "patch",
"published_at": "2026-07-25T18:48:00Z"
},
{
"tag": "v0.14.0",
"kind": "minor",
"published_at": "2026-07-24T11:53:18Z"
},
{
"tag": "v0.13.0",
"kind": "minor",
"published_at": "2026-07-21T20:13:41Z"
},
{
"tag": "v0.12.4",
"kind": "patch",
"published_at": "2026-07-17T04:16:40Z"
},
{
"tag": "v0.12.3",
"kind": "patch",
"published_at": "2026-07-17T03:19:45Z"
},
{
"tag": "v0.12.2",
"kind": "patch",
"published_at": "2026-07-17T01:50:29Z"
},
{
"tag": "v0.12.1",
"kind": "patch",
"published_at": "2026-07-17T01:18:53Z"
},
{
"tag": "v0.12.0",
"kind": "minor",
"published_at": "2026-07-17T00:31:01Z"
},
{
"tag": "v0.11.2",
"kind": "patch",
"published_at": "2026-07-16T22:17:24Z"
},
{
"tag": "v0.11.1",
"kind": "patch",
"published_at": "2026-07-16T21:54:07Z"
},
{
"tag": "v0.11.0",
"kind": "minor",
"published_at": "2026-07-16T21:40:02Z"
},
{
"tag": "v0.10.4",
"kind": "patch",
"published_at": "2026-07-16T14:18:33Z"
},
{
"tag": "v0.10.3",
"kind": "patch",
"published_at": "2026-07-16T12:28:07Z"
},
{
"tag": "v0.10.2",
"kind": "patch",
"published_at": "2026-07-16T11:19:38Z"
},
{
"tag": "v0.10.1",
"kind": "patch",
"published_at": "2026-07-14T09:31:01Z"
},
{
"tag": "v0.10.0",
"kind": "minor",
"published_at": "2026-07-11T18:10:10Z"
},
{
"tag": "v0.8.0",
"kind": "minor",
"published_at": "2026-07-05T23:52:24Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2026-07-05T00:50:10Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2026-07-04T00:41:43Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2026-07-02T20:01:51Z"
},
{
"tag": "v0.2.2",
"kind": "patch",
"published_at": "2026-07-02T18:21:22Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2026-07-02T14:48:05Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2026-07-02T14:37:10Z"
}
],
"recent_commits": [
{
"oid": "0195be77e753248dbac9381fa4382cada4814459",
"body": "…-op on an in-process bus\n\nMemoryBus.consume() drains a queue that lives in the publisher's memory.\nRun it in a SEPARATE process and it finds nothing, returns, and the\nprocess exits 0 — which under a container restart policy is an infinite\nloop that looks like activity and delivers nothing. 0.11.0 m\n[…]\n-allow-in-process keeps the legitimate single-process test path. Backends\ndeclare the property themselves via BusBackend.in_process.\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: stapel-core 0.14.2 — a consumer process must not silently no…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-25T20:17:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "09b1b4464cc7f3780f10aff99b8729c16086fcc3",
"body": "…s a pre-rename table\n\n0.8.0 renamed the app label stapel_tasks → stapel_taskstore and pinned\ndb_table to the historical name, calling it \"label-only, no data\nmovement\". The DATA didn't move; the migration STATE did. Any database\nthat had migrated before 0.8.0 records those rows under the old label,\n[…]\ns cover both paths against the real executor: absent table → created,\npre-existing table → adopted with its rows intact (1899 pass).\n\nCo-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: stapel-core 0.14.1 — the taskstore's initial migration adopt…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-25T18:48:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "657c38151d6fa265ac0dcbaa366fe9283cb857eb",
"body": "- verification: VerificationFactor.strength strong|weak (default weak —\n email code alone is not 2FA), describe()/strong_names()/strong_factors()\n- users: password_change_required + mfa_enrollment_required flags,\n auth_type 'login' (org-provisioned), StapelUsernameValidator — exactly\n one '/' as \n[…]\nremote error, degrade to membership+builtin\n role table on old workspaces)\n\n1897 tests (+41), ruff clean, migration-lint clean, wheel verified.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: stapel-core 0.14.0 — org-program Wave 0 primitives (additive)",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-24T11:53:18Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1a74cb188727b7474cc2105428cc8ac8a340cd46",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: stapel-core 0.13.0 (StapelImage descriptor + Н4 allow_blank)",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-21T20:13:41Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "1fa327ef81d5237fa722175c691318716965aa95",
"body": "DataclassSerializer mapped `description: str = \"\"` to a CharField that is\nrequired=False (has a default) but allow_blank=False (DRF default) — so the\nserializer REJECTED the very value it defaults to. That desynced from the\nDjango model (blank=True, default=\"\") and forced callers to omit the key\nrat\n[…]\ndeclared default is \"\", blank is a valid value.\n`allow_blank` also joins the field(metadata=...) override keys as an escape\nhatch.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(api): a str DTO field defaulting to \"\" now allows blank (libgaps Н4)",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-21T20:12:16Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d1b25da252a2e38672e6cc2192c2783fdc2f2e6d",
"body": "The single contract a renderer (@stapel/image <Image>) consumes for ANY image\n— CDN ladder, plain file, or external OAuth link — so it renders whether or not\na CDN is wired. A superset of RenderMetadata: adds a `source` tag and an\nalways-present top-level `url`, with `variants` = the ladder or [] (r\n[…]\nserializers so any\n ref-carrying serializer denormalizes an image next to the ref and\n drf-spectacular emits a stable component.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(media): source-agnostic StapelImage descriptor + DRF serializer",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-20T23:21:49Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "bb9e20bcee5f82015059f773a5385dce61350274",
"body": "stapel-auth 0.8.0 promotes an anonymous guest session via SSO JIT\nprovisioning and needs an accurate auth_type to record — reusing \"oauth\"\nor \"email\" for an SSO anchor would misreport how the account was\nactually established. Choices-only migration, no data change.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(users): add \"sso\" identity anchor to AUTH_TYPE_CHOICES (0.12.5)",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-20T00:17:01Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "817ecabfb76be00766d9da0fba4d041d5773ce57",
"body": "…cks (0.12.4)\n\ncdn-modularity.md §2.1/§5 (owner GO): image_type was frozen to a verbatim\ncopy of the legacy marketplace ImageType/AssetType enum, raising\nValueError at class-definition time for anything outside 6 hardcoded\nvalues — while the server (stapel-cdn 0.7.0+) already accepted any\nconfigured\n[…]\nred\n at all — catches the miттudei-class incident at manage.py check time\n instead of on the user's first \"Change avatar\" click in production.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cdn): unfreeze CdnImageField image_type — open string + lazy che…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-17T04:16:40Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6751d6904878c841511ab488fdb47127525aeecd",
"body": "…dy() (0.12.3)\n\nstapel_core.django's own eager AutoSchema import builds drf-spectacular's\nspectacular_settings singleton before a project's SPECTACULAR_SETTINGS\nassignment executes (settings.py opening with `from\nstapel_core.django.settings import *`), permanently pinning every schema\nthis process e\n[…]\no-effect when the order was\nalready correct. Same fix stapel-example-monolith previously had to carry\nlocally; it can now drop that local patch.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(openapi): patch drf-spectacular import-order bug in AppConfig.rea…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-17T03:19:45Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "72b971266a3e45825b2995a696a7bb7f71e3832a",
"body": "…ment check (0.12.2)\n\nThe live incident: nginx reserved the bare /calendar prefix for the backend,\nsilently killing the frontend's SPA page at that path. Canon (BACKLOG §37)\nwas already clear — a backend module owns only /<mod>/api/, /<mod>/swagger/,\n/<mod>/schema.json, /<mod>/admin/ — but nothing m\n[…]\negories, gdpr, listings, notifications, profiles, workspaces,\n mailtrap, agent, tasks, recordings, geo, video, reviews, currencies) is\n compliant. Fixing stapel-translate is a separate repo/release.",
"is_bot": false,
"headline": "feat(mounts): §37 surface topology — reserved_paths() + mount-contain…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-17T01:50:29Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d9e2c65f4da77a844420bd10b7d175444ea5524f",
"body": "RedisStreamsBus (bus/backends/redis_streams.py) rounds out the\nkafka/nats/redis_streams standard set (владельческая директива). One\nRedis stream per topic (XADD), one consumer group per subscriber\n(XREADGROUP+XACK, group naming matches Kafka's group.id / NATS's durable\nname), XAUTOCLAIM reclaims ent\n[…]\nUTOCLAIM semantics\nwithout a live server: publish/consume round trip, ack, retry, DLQ,\npending redelivery after a simulated crashed-consumer claim, checks,\nconfig. 98% line coverage on the new module.",
"is_bot": false,
"headline": "feat(bus): Redis Streams backend — third standard comm-bus transport",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-17T01:18:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9275e4f9bc3ebabda15a02c0495911ef96aa3cf3",
"body": "…RON_HOST, flat captcha, wire user block\n\nRemoved (breaking, minor per house law):\n- stapel_core.kafka transport (consumer/producer/config/health) + bus re-exports\n + BaseKafkaConsumerCommand alias; package keeps only EventType/TOPIC_* constants\n- EventType.TRANSLATIONS_CHANGED / TOPIC_TRANSLATIONS\n[…]\nAC no-mandate behavior, get_config ConfigKeyUnknown path, nav prefix\nfallback — live runtime, not compat. 1775 tests green; verify errors 32→18.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(release)!: 0.12.0 — legacy sweep: kafka transport, JWT shims, I…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-17T00:31:01Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f5066335b7710ce80bec5bde3099000ca6c530cb",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(release): 0.11.2 - error params/language + bus singleton lifecycle",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T22:17:24Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bf2d1136c9fa14fab08512e9ef6e5ab03405cff3",
"body": "…`error`\n\nLive finding: the backend sent a Russian `error` message and the frontend\nhad no way to know whether that text was safe to show verbatim or needed\ntranslating - COMMON_ERRORS templates are always English, but the DRF/\nDjango-ValidationError fallback (str(detail)) renders in whatever locale\n[…]\ns unchanged: the frontend still\ntranslates by localizable_error+params; error stays a fallback/debug string,\nnow with a known language attached.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(errors): error_language field tells the client whether to trust …",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T22:16:05Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c05371e589f21fae61042437eab3aad068f76cee",
"body": "…gth, etc)\n\nDRF's ErrorDetail carries only .code (e.g. 'max_length') - the actual limit\nlives on the field that raised it (serializer.fields[field_name].max_length),\nso a catalog consumer (frontend i18n) could never render \"no more than N\ncharacters\" for a max_length/min_length/max_value/min_value/.\n[…]\nain rest_framework.serializers.Serializer that never attaches itself\ndegrades to the field-name-only params exactly as before - purely additive.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(errors): validation error params carry the field's limit (max_len…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T22:14:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f1bf497c36256ac0ce999993d0abff0fea08409c",
"body": "get_bus() resolves the backend lazily on first call, but then holds it as a\nmodule-level singleton for the rest of the process. If something calls\nget_bus() once before a later override_settings(STAPEL_BUS_BACKEND=...) (or\nthe pytest-django settings fixture, used throughout this suite), the first\nre\n[…]\nis read once\nat boot and doesn't change without a restart - this specifically closes the\nruntime-reconfiguration gap (tests first and foremost).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(bus): auto-invalidate cached backend on settings change",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T22:11:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "2b451ea314e23524b266272b1f682901dc75292a",
"body": "…(0.11.1)\n\nFollow-up to the 0.11.0 kafka-default postmortem: get_config's Required\nwas only ever enforced the first time some code path called get_config(key)\n- possibly never, for a key nothing reads through the config seam yet.\nNew stapel_config system check (E001) walks every required key (CONFIG\n[…]\nnd of drift that left STAPEL_BUS_BACKEND's CONFIG.MD row still pointing at\nkafka after 0.11.0 moved the real default to memory (fixed here too).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(config): required keys enforced at boot + code-sourced metadata …",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T21:54:07Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5d56e7890a62c951bb31178bec7a84a0bf982ce8",
"body": "…av (0.11.0)\n\nBREAKING: STAPEL_BUS_BACKEND now defaults to the in-process MemoryBus\ninstead of kafka. Live run finding: request_notification (OTP emails)\nsilently never left the process because confluent-kafka wasn't installed\nand the ModuleNotFoundError was swallowed by fail-soft callers. Kafka/NAT\n[…]\nndex links each module's admin section, Swagger and schema, and a\nstaff-gated GET /nav exposes the same structure as JSON for a future\nfrontend.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(bus)+feat(nav): memory default over silent-kafka + admin module n…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T21:40:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "bd6eb1b31f677a46ac3be46747bcc8e1f713609b",
"body": "…-catalog, reference get_presenter() consumer (0.10.4)\n\ndeclare_swap()/declared_swaps() (swappable.py): import-time registration\nof swap points, independent of first resolution; get_model/get_presenter\nrecord their defaults lazily as a backstop; declarations survive\nclear_swap_cache().\n\nAuto-catalog\n[…]\n\n\nTests: test_presenter_catalog.py (19) — declarations, catalog entries,\nrendering, command incl. --check, profile block incl. swap. 1723 green.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(presenters): §55 slice 2 — swap declarations, PRESENTERS.MD auto…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T14:18:33Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6080e84d51d1a97ac98564b958c7ed980ce03479",
"body": "…hs (§61, 0.10.3)\n\nimages-and-cdn.md §1/§1а/§6 п.6:\n- RenderMetadataProvider Protocol + pil (default, zero-infra ImageField\n path) and cdn (delegates to cdn.describe comm Function) providers;\n dotted-path escape hatch; describe(ref) facade — backend swap is\n config (STAPEL_MEDIA / STAPEL_MEDIA_BA\n[…]\nrridable via STAPEL_CDN_MEDIA_URL\n\n1705 tests green (incl. 33 new media + field tests), ruff clean; wheel\nverified to carry stapel_core/media/*.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(media): stapel_core.media — one media interface, two storage pat…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T12:28:07Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "85523e09b71b9f50068ebf01b9e497e3cf4d1a92",
"body": "…rojections-and-composition §1); real info.version via package= (api-versioning step 0)\n\n- Projection.live_query / force_mode; resolve_mode() by owner app label\n (get_app_config, not is_installed — CTO-review note)\n- validate_registry(): local valid without model but requires live_query;\n remote r\n[…]\ndes\n- get_spectacular_settings(package=...): info.version from installed\n distribution metadata; explicit version wins\n- chore(release): 0.10.2\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(projections): local/remote colocation modes + read() accessor (p…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-16T11:19:38Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "dbde3a6b29b153cbfc08c4f3865ac4c94355f4d0",
"body": "The avatar StringDataRightTruncation fix (5dc6c04) shipped after v0.10.0 was\ntagged without a version bump; cutting 0.10.1 now so the fix is installable\nfrom PyPI ahead of the stapel-auth companion release.\n\nCo-Authored-By: Claude Sonnet <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(release): 0.10.1 — patch release for avatar URLField widening",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-14T09:31:01Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5dc6c0495cb9503a3b894ac3197b491aa0a2c958",
"body": "…r avatar URLs (Google/GitHub) exceed the URLField default varchar(200), causing StringDataRightTruncation on OAuth signup\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(users): widen avatar URLField 200→500 + migration — OAuth provide…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-14T08:57:43Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7b0eb1e6c181d9a20de741b98cbf8f2cfd5dbd00",
"body": "…s list — was missing → clean install/CI ImportError, publish blocked (packaging drift, explicit list)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(packaging): add stapel_core.django.projections subtree to package…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-11T18:10:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "0c3c2e869cad3d9d115b2ade7cd5e92b94e88de1",
"body": "… (§55 slice 1)\n\nPresenter (django/api/presenters.py) on top of the existing\ndjangorestframework-dataclasses dependency and StapelDataclassSerializer:\nmodel + as-is fields (type/description from the DAO) + custom_fields\n(PresenterField: rename/transform/nest another Presenter's dto) ->\npresent(dao) \n[…]\n end-to-end in tests/test_presenters.py — present(),\ngenerated schema, and presenter replaced by a host subclass via\nSTAPEL_SWAP config, no fork.\n\nCo-Authored-By: Claude Sonnet <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(presenters): DAO→DTO presenter primitive + swappable indirection…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-11T15:41:32Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "0cbec0b3900fd7f55d66cf936a5a4d087e4c16cc",
"body": "get_config(key) (stapel_core.config) is a thin generalization of get_secret:\nenv-source keys read os.environ, vault-source keys delegate to the\nsecret-provider seam (get_secret). Routing table is a CONFIG.MD markdown\nregistry — {Key | Source: env|vault | Purpose | Required | Default}, grouped by\n`##\n[…]\ne tables/owners/required/default/bad-source, env|vault\nrouting, fail-closed, discovery+cache, core's own registry). Full suite green,\nruff clean.\n\nCo-Authored-By: Claude Sonnet <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(config): get_config over the secret seam + CONFIG.MD registry (§2)",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-11T14:13:01Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "26607226849f5102851c391ece85961a69ae42e7",
"body": "…10, Q2)\n\nFourth comm primitive alongside Action/Function/Task. Declare which Action\ntopic(s) feed which local read-model table and how each event upserts a row;\nthe framework gives generated idempotency + ordering (an event applies only\nif its position — sequence_field, else event timestamp — is st\n[…]\nommand. Suite 1598→1618 green.\n\nMinor bump 0.9.0 → 0.10.0; MODULE.md + CHANGELOG documented with an abstract\ncatalog-likes-from-engagement example.\n\nCo-Authored-By: Claude Opus <noreply@anthropic.com>",
"is_bot": false,
"headline": "comm: Projection primitive — event-carried read-models over Action (§…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-09T23:13:55Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8480d2b627493a17c350bdcc84978c4c9e176ec0",
"body": "…(gap G14)\n\nWebSocket/ASGI counterpart of the HTTP JWT stack. `JWTAuthMiddleware`\n(+ `JWTAuthMiddlewareStack` factory) validates the token with the SAME\n`jwt_provider` — same signing config, token/user blacklists, and\n`get_or_create_user_from_jwt` sync — then populates `scope[\"user\"]` and\n`scope[\"st\n[…]\nels\n raises a clear ImportError.\n\nMinor bump 0.8.0 -> 0.9.0. Tests: tests/test_jwt_channels.py (28), 100% module\ncoverage; full suite 1598 passed.\n\nCo-Authored-By: Claude Opus <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(jwt): Channels JWT auth middleware over the shared jwt_provider …",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-09T21:26:19Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "b7b64cc83362af2783d5ca07c90401dd485f47a1",
"body": "Adds `make migration-lint` and a CI step next to Lint/emit-check/Import\ncheck. This repo's own migration finding (phone AlterField narrowing) was\ntriaged and marked in the prior commit — `make migration-lint` is green\nnow. The CI step ships commented-out with a TODO: no module repo's CI\ninstalls sta\n[…]\nthe new org, no git-install\nmechanism wired anywhere). Run `make migration-lint` locally / at\nrelease-cut time until CI can fetch stapel-tools.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci: wire migration-lint gate (release-management.md §3)",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-09T11:33:45Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "47f3e2e378426af2cc3369cbf5602c0387c51660",
"body": "…er_phone)\n\nstapel-migration-lint --strict flagged the phone AlterField narrowing\n(20 -> 18 chars) as destructive without a contract-phase marker. This\nmigration shipped in stapel-core's first commit/release (extracted from\nthe monolith); no released version of this package predates it, and\ndjango/u\n[…]\nre normalized via RunPython while the column is still varchar(20), before\nthe AlterField narrows it. Marker/comment only, no operation changes.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(migrations): mark verified expand/contract finding (0004_alter_us…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-09T11:29:17Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "068d82f22e1f8611106d139e3c4a02eb76c7b639",
"body": null,
"is_bot": false,
"headline": "docs: add PyPI badge to README",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-08T14:29:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b509835954a8af9138f945b34e9e0e5bfd5137bc",
"body": "Rewrite legacy-provenance references in docstrings, comments, and the\nchangelog for consistency.",
"is_bot": false,
"headline": "docs: refactor provenance wording in comments and changelog",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-07T13:23:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c1e12853a9575ce4418acb3ef46a95456f9e7d6a",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: CHANGELOG + MODULE.md for the flow Gherkin projection",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T16:38:38Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "a06bbe399989a3aca37da7799fcaf5fa803ceaca",
"body": "…drift gate\n\ndocs/examples/auth-flow-features/: committed snapshot (stapel-auth\nflows.json + en/ru catalogs) → generated en/ru bundles (.feature ×3 +\nplaywright-bdd step-defs + fixtures). tests/test_flow_feature_reference.py\nis the release-gate drift check (regenerate-and-diff, byte-stable;\nSTAPEL_R\n[…]\ncore because stapel-auth is read-only\nfor this change; wiring features/ + the gate into stapel-auth proper is\nthe module maintainer's follow-up.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(flows): reference Gherkin bundles for the 3 stapel-auth flows + …",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T16:33:28Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "63f693e68570654ebb16cc2e59f9c0ac7f571878",
"body": "…e Gherkin projection\n\nload_flows_json rebuilds (FlowSpec list, endpoint index) from the exported\nmachine artifact — the Gherkin projection can now run from a committed\nflows.json (codegen output, reference snapshot) without booting the Django\ninstance that produced it; loading never touches the glo\n[…]\n by\ngenerate_flow_features and json-based generation. Parity test: live\nregistry and json-loaded flows render byte-identical .feature/step-defs.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(flows): flows.json loader + shared language-bundle writer for th…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T16:31:38Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "fc15e62c42b8bd42d85023c55daa4125e8b4c4c8",
"body": "…e-stable bundles\n\n15 tests: positional Given/When/Then mapping (And-folding), ru dialect\nheader + localized keywords, unknown-language fallback, single-line note\nfolding, JS-regex escaping, Django→OpenAPI path conversion, HTTP steps\ncalling the typed client, honest TODOs (parametrized paths, unrout\n[…]\nd\nviews, testid-less UI steps, comm effects), i18n-resolved regexes, and\nthe bilingual generate_flow_features bundles reproducing byte-for-byte.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "test(flows): Gherkin generator — dialects, step-def client calls, byt…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T16:27:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "94c0a8f3338528a9669302c44e66d5ea04ebcc5d",
"body": "… generator\n\nflow-system.md §3 (wish #3): the flow is the source, the .feature is a\nprojection. stapel_core.flows.gherkin renders one localized Feature per\nflow (positional Given/When/Then over the resolved i18n step notes, ru\ndialect header for non-en) plus a playwright-bdd step library: HTTP steps\n[…]\nflow_features writes one\nself-consistent bundle per project language (byte-stable, drift-gate\nready — same discipline as generate_project_docs).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(flows): Gherkin projection — .feature + playwright-bdd step-defs…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T16:27:30Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "8d032b51fe021a77c808efff2114885b5c718eec",
"body": "…taff mandate (AS-7)\n\nNew subsection under the Staff mandate: day-1 no-op guarantees (opt-in by the\nfirst role, additive-only migration, step-up self-disabling), the five\nindependent enabling steps (backends -> roles -> declarations ->\nStapelModelAdmin -> step-up), the AS-2 sync note for local staff\n[…]\nt ordering for\nmigration scripts), the exit path from the legacy Staff group via\naccess_report, and the symptom -> system-check diagnostics map.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(MODULE): migration guide — moving an existing project onto the s…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T12:37:36Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6797548af74611325cf8ad1dfd48b47b421f5fb3",
"body": "…te AS-6)\n\nQ8a: step-up is part of the standard preset (delete=HIGH), enforced by\ndefault — not opt-in. A HIGH-required admin mutation needs a fresh\nverification grant on top of the mandate; the mandate says a role *may*\nact, step-up says it was re-proven recently.\n\n- stapel_core.access.stepup: STAP\n[…]\n5 (enforced but degraded). No\n migrations (policy + signals + admin behavior only).\n- 31 new tests (1550 total green); ruff + emit-check clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(access): step-up on HIGH admin ops + audit forwarding (admin-sui…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T11:30:12Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4eed59dfd371a34ffe1778884ef57e3b79dd86c0",
"body": "…AS-4 §2 arbitration)\n\nThe AS-4 review (§2) rejected the original current_dashboard_url heuristic —\n\"first admissible dashboards/tools link under the current URL_PREFIX\" — as\ntoo implicit for a mechanism contract: a module should say it owns the\nservice dashboard, not have it inferred from URL shape\n[…]\nings-overlay flag,\n fallback preserved with no flag set, two-flags ordering, duplicate-flag\n warning. MODULE.md documents the selection order.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(nav): explicit service_dashboard flag for current_dashboard_url (…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T11:07:49Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c6c90f5f19bcd818200f63676b2ee025dd39060e",
"body": "…-suite AS-4)\n\nService navigation is no longer hardcoded in the framework — the marketplace-legacy\nSTAPEL_SERVICES list in core/config.py and the Tools/Monitoring/dashboard links\nbaked into base_site.html + the Swagger inject were policy in a mechanism\n(§2.1). Both move to deploy-config.\n\n- stapel_c\n[…]\nting for\n staff/superuser/non-staff/anonymous, empty registry, monolith vs micro,\n malformed-config checks). MODULE.md nav section, CHANGELOG.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(nav): STAPEL_SERVICES env-JSON + NAV_LINKS merge-registry (admin…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T10:55:27Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6ef446fd681b397b270b4d367233c18dbf061d4f",
"body": "…PEL_ADMIN, core ops admins (admin-suite AS-3)\n\nEnforcement through the AS-1 backend, not app-list cosmetics: a direct\n/admin/app/model/ URL answers 403 per (declaration x clearance). The admin\nlayer adds what has_perm cannot express — ops read-only even for superusers\n(A5 bypasses the mandate), sec\n[…]\nts: category x role x operation matrix via real admin client on direct\n URLs, masking, SHOW_OPS_MODELS, overrides, contrib (51 new; suite 1479)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(admin): category-driven admin visibility — StapelModelAdmin, STA…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T10:02:07Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "61527add4607b338c9aa3b1936f0b40a49e76cec",
"body": "…AS-2)\n\nConsumer half of the staff-role transport (producer: stapel-auth 6fdb6f9).\nAuth is the single source of truth for staff status (в.3):\n\n- staff_roles JSONField on AbstractStapelUser (+ users/0006 migration): the\n shadow copy of the staff_roles JWT claim.\n- serialize_user_to_jwt_data emits th\n[…]\nmade the group-source\nfallback unreachable (field is now authoritative). 1428 core tests pass;\nstapel-auth 1194 stay green against the new core.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(jwt): staff-roles sync-down REPLACE + claim bridge (admin-suite …",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T07:08:50Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "bfe0941833b7081fdb3e223340ce505269846b79",
"body": "…-module targets, stop hardcoding root-relative paths\n\nRoot cause (live, sub-path-mounted project): LOGIN_URL and every\ncross-module URL target were hardcoded root-relative, so a project\nmounted whole under a prefix redirected anonymous admin visitors to\n/admin/login/ -> /auth/admin/login/ -> 404.\n\n\n[…]\n chain under an\n include prefix (tests/test_mounts.py, 38 tests). MODULE.md section +\n no-absolute-paths anti-pattern; CHANGELOG [Unreleased].\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(mounts): canonical URL mount registry — derive LOGIN_URL & cross…",
"author_name": "Victor Pasenchuk",
"author_login": "Pasenchuk",
"committed_at": "2026-07-06T05:40:20Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "21a5c0607eb5539d7890b990ad1ad07bb7d18459",
"body": "…8n-shipping wave 0)\n\nGeneralize the flow-i18n contour into stapel_core.i18n over content domains\n(flows, errors, …): per-app translations/<domain>.<lang>.json catalogs\ndiscovered over INSTALLED_APPS, merged later-wins (fork-free host override);\nSTAPEL_I18N (LOCALES single project-languages knob, EX\n[…]\ns).\n\nTests: discovery/merge, provenance roundtrip, seed/llm/approve/stale,\nparams + override gate, error-docs, command wiring. Full suite green.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(i18n): domain-agnostic content catalogs + errors ru pipeline (i1…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-06T04:38:24Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "36b82bc1dea0845bb73db95be0c226c9e5409377",
"body": "… TTL cache)\n\narch-stapel-vault Part 1. get_secret(name, default=…) resolves a secret\nthrough a dotted-path provider seam STAPEL_SECRETS[\"PROVIDER\"] (canon like\nAUDIT_SINK/ROLE_SOURCES). Default EnvSecretProvider = os.environ — local dev\nand the minimal preset are unchanged, zero new deps. Pointing \n[…]\n, fail-closed, env transparency, bootstrap,\nprodguard compat, checks). Full suite 1356 passed, ruff clean, emit-check clean.\nVersion NOT bumped.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(secrets): SecretProvider seam in core (env default, fail-closed,…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-06T03:15:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "144a2429b104968c572f494999e1c68d2e9e62b4",
"body": "stapel_core.access: MAC for staff/admin — has_perm is a computed function\nof (@access declaration x role clearance), no Permission-string generation.\n\n- @access decorator + presets (standard/sensitive/ops/secret); undecorated\n model = implicit standard; admin category in the same declaration\n- Mand\n[…]\n); runtime role\n definitions reserved behind a flag with a written mini-design (в.1)\n\n78 new tests (1336 total green); ruff + emit-check clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(access): staff mandate — computed admin rights (admin-suite AS-1)",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-06T03:01:37Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "fe1712664f9b49ebebe7a82d7ccfd4ed47216785",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ci): editable test install + publish gated on tests (§7.5-7.6)",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-06T02:36:31Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "52e02b35ec4398c42224ac877dc2f99e50848817",
"body": "Add the backend companion of schema.json/flows.json: a `generate_error_keys`\nmanagement command that emits errors.json — the byte-stable registry of every\n`error.<status>.<name>` key an instance can raise, as an array of\n`{code, status, params, remediation, en}` sorted by code. Shape matches the\nfro\n[…]\nr own remediation, and captcha en text\nis aligned to the canonical fuller copy so a re-declaring service produces an\norder-independent artifact.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(errors): errors.json codegen artifact + declarative remediation",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-06T02:16:30Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "4a851b0e3fce573a23a7ca90d0daebdb3a1511ad",
"body": "stapel_core.django.prodguard.guard_secret/guard_db_password reject known\n.env.example placeholders (change_me*, django-insecure-), too-short\nSECRET_KEY/JWT_SECRET_KEY (<50 chars), and the default/placeholder\nPOSTGRES_PASSWORD — the previous inline guard in generated prod.py only\ncaught an empty or django-insecure- prefixed secret. Wired into\nstapel-tools' prod settings templates in a companion change.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(django): add prod-guard for placeholder/weak secrets (SEC-4/B2/B6)",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-06T01:33:14Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "aa595b78f6aa18da27798022037f46ecb831dbd6",
"body": "…6.0 (904f3a8), gateway as 0.7.0\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: restore [0.6.0] heading in CHANGELOG — eventstore shipped as 0.…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T23:52:24Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "8972a36c17e368b7b6350cedf3d0102f7c5bb98d",
"body": "…classifiers)\n\nstapel-core was the only workspace lib missing [project.urls] and carried\nthe old minimal classifier set. Align to docs/library-standard.md §4\nartifact checklist and the 19 sibling libs: add Homepage/Repository/\nDocumentation/Changelog/Issues and the full classifier matrix (License\nOS\n[…]\nce, Development Status 4-Beta, OS\nIndependent, Python 3::Only, 3.11-3.13 matching CI). Metadata-only; no\nversion bump (0.8.0 not yet published).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "packaging: complete PyPI metadata for 0.8.0 (project.urls + standard …",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T23:48:35Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "35ff95702ca72d34bbc9cdc9fae4d03a523e326b",
"body": "…tore (0.8.0)\n\nThe internal comm-Task persistence app collided on the Django label\n`stapel_tasks` with the new generic stapel-tasks module (0.1.0), which owns\nthat canonical label. Two apps can't share a label in one INSTALLED_APPS, so\ncore vacates to `stapel_taskstore` (docs/tasks-module.md §2/§11)\n[…]\ntogether in one\n INSTALLED_APPS (subprocess, since Django configures once per process).\n\nMinor bump — label is part of the public app contract.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor(taskstore): rename Django label stapel_tasks -> stapel_tasks…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T20:53:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e575a6dcc1f1c748afd0f852d99e436a95714ec9",
"body": "…it (0.7.0)\n\nstapel_core.gateway (Studio SN-4, studio-design §2.3 / system-design §5.9):\nthe OSS mechanism of \"capability, not credentials\" — concrete verbs and\npolicies stay in the deployment (Studio, private).\n\n- Verb = name + mandatory JSON args schema + policy {tiers, rate_limit,\n require_confi\n[…]\nn mandatory, fails closed without jsonschema\n (extra stapel-core[gateway]).\n\n96 new tests (1231 total). Root export stapel_core.gateway (lazy).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(gateway): privilege gateway mechanism — verbs, scope tokens, aud…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T20:41:48Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "904f3a82133febd6a1bb83163680c1d1ff5a66de",
"body": "…nd + buffer/rollup/retention (0.6.0)\n\nNew `stapel_core.eventstore` seam (Studio SN-3′, docs/data-storage-and-observability.md\n§1; studio-design §3 three storage contours): one primitive for the many\nhigh-volume append-only streams (LLM-call ledger, gateway audit, analytics,\ndelivery logs) — written\n[…]\nrtition command;\n SQLite minimal profile degrades to one plain table (documented).\n\nBump 0.5.1 → 0.6.0. CHANGELOG, MODULE.md. Base 1101 → 1135.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(eventstore): append-only stream primitive — ABC + Postgres backe…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T20:07:55Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "22e6649ac3eb55313777a06a319357aba6dd23f3",
"body": "…oncurrent issuance (0.5.1)\n\nReview H-3 (catalog feature editor): RevisionMixin.save bumped the in-memory\nrevision on every save but never added it to update_fields — scoped saves\nemitted a revision that was never persisted, and the number was reused by the\nnext content change, so sync clients follo\n[…]\no,\none-shot-iterable update_fields, nested-atomic regression, 8x5-thread\nuniqueness (sqlite-compat). Suite 1101 passed; ruff + emit-check clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(revision): phantom revision on save(update_fields=...) + locked c…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T19:50:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d6b8b02cfcb359154daf4821bd18e9059a9da1fb",
"body": "…gual trees (flow-system.md §4)\n\nFLOW_DOC_RENDERER seam (default DefaultFlowDocRenderer): per-flow markdown\nwith a GitHub-native mermaid step diagram, numbered steps and an Endpoints\ntable carrying serializers + the step-up verification contract. Renderer\nchrome is localized (en/ru; unknown -> Engli\n[…]\n makes the regenerate + git diff --exit-code release-gate\nmeaningful. New settings FLOW_DOC_RENDERER, DOC_LANGUAGES; additive\nthroughout. 0.5.0.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(flows): SA-document renderer — mermaid + endpoint tables + bilin…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T19:35:15Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "eef94ba40ba8689d92eeb0c77cb02ee803b12fdb",
"body": "….4.1)\n\nDefensive review findings (low). _breaker_* now take _provider_lock for all\nstate access — the failure counter is a shared read-modify-write, so under a\nconcurrent fail-open flood unlocked increments dropped counts and the breaker\nopened later than its threshold; the module comment claiming \n[…]\ngs reconfiguration re-warns instead of staying silent for the\nwhole process. Behaviour: exact, faster breaker trip + log hygiene; no API change.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(netintel): lock circuit-breaker state + reset warned-providers (0…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T19:03:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "1b38fbd2d1098cdcac6067333cd146fa0520baa8",
"body": "…m.md §2)\n\nFlow/step texts become i18n keys (implicit flow.<id>.title /\nflow.<id>.step.<order>.note, explicit *_key override); the in-code literal\nstays the canonical English source and the fallback — literal-only flows\nwork unchanged. flows.json now carries the keys alongside the literals\n(language\n[…]\n → source literal. generate_flow_docs\ngains --lang/--llm/--llm-cache; check_flows flags colliding step keys.\n\nMinor bump 0.4.0 (pre-1.0 semver).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(flows): i18n keys for flow texts + resolution engine (flow-syste…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T18:32:15Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c6c5b4bf01bf5283128c4d8868e5be9a4a27a9cf",
"body": "Reliability/correctness hardening of the builtin IP-classification +\ncaptcha-tiering defense (internal review findings H1/H2/M1/M3/L1 +\nL2/L3/M2 docs). No behavior-offensive changes; all defensive.\n\nH1 load resilience: provider errors now negative-cache the unknown\nprofile for a new short NEGATIVE_C\n[…]\nmoization,\nIPv6/garbage normalization, no_env targeting; updated negative-cache and\nclient_ip-trust-model expectations. 1064 passed, ruff clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "netintel/captcha: harden anti-abuse seam for load & concurrency",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T17:30:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "9056af8f039e5090ff611863fd801311a9ade83a",
"body": "… emit-check gate (0.3.3)\n\nTwo module repos independently broke the outbox guarantee the same two\nways (categories C1: swallowed emit failure; listings L2: save and emit\nin separate transactions). Turn the discipline into mechanism:\n\n- comm.mutate_and_emit(): mutation + emit in ONE transaction; yiel\n[…]\n new _requeue().\n- Tests: test_emit_atomicity.py (15, incl. test_failing_emit_rolls_back\n class) + test_emit_check.py (18). Suite: 1053 passed.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: outbox atomicity as a seam — mutate_and_emit(), runtime guards,…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T12:58:47Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "57fab122f4cebd06f757f9541bd98e52a2103cf9",
"body": "…dditive)\n\nstapel_core.netintel (classify_ip seam) + captcha challenge-policy tiers.\nBackward-compatible (NullProvider default = unknown = today's behavior; all\n20 legacy captcha tests pass unchanged) -> patch bump. 1018 tests. Queued for\nFable re-review (docs/fable-review-queue.md).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: release 0.3.2 — netintel IP-classification + tiered captcha (a…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-05T00:50:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7cf091a07d53ae7d21c6d0974918a2ccc04f574c",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: gitignore *.err build scratch",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-04T20:03:21Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "104acdc2a95c151cecabe82b9ff8698468799c17",
"body": "Implements docs/geo-network-trust.md §0 and §2:\n\n- stapel_core.netintel: classify_ip/country_of/client_ip on a dotted-path\n provider seam (STAPEL_NETINTEL[\"PROVIDER\"], default NullProvider).\n Built-ins: MaxMindProvider (GeoLite2/GeoIP2 mmdb, optional extra\n netintel-maxmind) and HttpJsonProvider \n[…]\nion, level,\n allowed). Unconfigured netintel reproduces the historical binary\n behavior exactly; CaptchaMixin and existing backends untouched.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: netintel IP-classification seam + tiered captcha challenge policy",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-04T09:10:38Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "55703ca620476add8e2abdc1738c8b55ec57c274",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: release v0.3.1",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-04T00:41:43Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "2b1798634ddd44b96a652dd6c99d188b3a13fb4c",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: add MODULE.md — agent-facing extension-point map",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-03T16:05:40Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "a6aa18d638af734c33afa7fd566c4ff8a657ddbe",
"body": "…late topic deprecated\n\n- schemas/emits/notification.requested.json describes the real payload\n incl. optional content_html/content_text; request_notification validates\n shape at the edge (type-registry membership stays consumer-side + lint —\n split documented in the schema)\n- TOPIC_TRANSLATIONS_CHANGED / EventType.TRANSLATIONS_CHANGED deprecated\n in place (kept for pinned deployments)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: notification.requested contract + edge validation; legacy trans…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T21:17:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "8c70942c55e686492921fe0c6bc3d601808f4b2c",
"body": "…%, migrations/tests ignored\n\nCodecov's default patch target=auto compares every diff against the\nproject average — a bar that only drifts upward and fails legitimate\nlow-testability diffs. Policy codified in system-design §7.13.5.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci: codecov policy — project ratchet (0.5% tolerance), patch floor 80…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T20:59:30Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "b255da07880a0f4bc9158063e25891dd9d88b14b",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: __version__ reads package metadata instead of a stale literal",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T20:08:58Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "0107c13e8b0a01538c40768bbcc29be6f9032cb5",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: 0.3.0",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T20:01:51Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "15ed1fceb4b21255fb89495562209a4c5f151bff",
"body": "- stapel_core.verification: attach OTP/TOTP/passkey requirements to any\n endpoint via @requires_verification(scope, factors, max_age) — 403 with\n a structured challenge envelope, interchangeable factors, server-side\n grants per user+scope (or stateless X-Verification-Token), policy\n overrides vi\n[…]\n some topics\n to NATS, others to Kafka/memory) behind the same BusBackend facade\n- comm: task dispatch and action/config refinements with tests\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: step-up verification framework + per-topic bus routing",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T19:56:38Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "ed1c544f518fddb65c0b1aa41b587be82bc5febd",
"body": "phonenumbers (User.save phone E.164 normalization) and celery (the\noptional comm.tasks executor) are exercised by the suite but were declared\nnowhere, so 3 tests failed on the clean CI runner. phonenumbers is now a\nruntime dependency (silent degradation otherwise); celery lives in the dev\nextra and CI installs .[dev].\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: declare phonenumbers dep + celery dev-extra for CI",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T19:09:59Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "896860d04830e3caf350a7cc1c79aa7e25f39a5e",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: 0.2.2",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T18:21:22Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "da96930199df300e2fbfd475694b9f187d0dfe2d",
"body": "EndpointInfo carries the handler attribute name (action name for\nViewSets, http verb for APIViews); the postprocessing hook resolves the\nreal handler — @flow_step/@requires_verification on ViewSet actions now\nreach x-stapel-flows / x-stapel-verification.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: flows/verification OpenAPI hook resolves ViewSet action handlers",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T15:42:54Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "a9e3be82471ddde1ed4cf5929a9165d4c93175d6",
"body": "COMMON_INSTALLED_APPS/COMMON_MIDDLEWARE require corsheaders, but the\nwheel did not pull it in — pip-mode installs failed at django.setup().\nFound by the examples' switch to the real user install path.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: declare django-cors-headers dependency (release 0.2.1)",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T14:48:05Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "28fbf156f4da5ce84325b0448a527db39004b1f4",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: 0.2.0",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T14:37:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e66b454221fbf70988ab3fb71231a8c947614227",
"body": "…ublic API\n\nFlows (stapel_core.flows) — the self-documentation contract:\n- Flow objects with http/action/function/task/human steps; @flow_step\n attaches an endpoint to any number of flows; autodiscovery from\n INSTALLED_APPS flows.py\n- manage.py generate_flow_docs renders SA-grade markdown per flow\n[…]\nte docstring\n- coverage 52% -> 99% (354 -> 887 tests): jwt, infra, api, comm gaps\n- consume_actions bridge included (bus -> @on_action registry)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: flows doc engine + step-up verification + 99% coverage + real p…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T14:33:27Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "13177b23860a4e3251475f6a1409fbc62bdc24f1",
"body": "…action delivery\n\nIn ACTION_TRANSPORT=bus deployments, emitted actions land on Kafka topics\nnamed after the action, but nothing delivered them to @on_action handlers\nin other services. consume_actions subscribes to every locally subscribed\naction name (or an explicit --topics subset) and dispatches events to the\nlocal registry; handler failures re-raise so the backend's DLQ applies.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: consume_actions — bus-to-registry bridge for cross-service @on_…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T13:53:00Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "c0dcfaa0d3511144dac74991f6909e8980301ef1",
"body": "…R templates, CI matrix\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: community files — contributing guide, security policy, issue/P…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T10:33:28Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f485486c632c201cb7571c3c7965dc8fe135c74a",
"body": "…ract user, topology settings, security)\n\nTask (third comm primitive, docs §2.1): start()/status()/@task_handler —\nasync named operations with persistent state (TaskRecord), outbox-backed\ntask.requested, atomic claim (idempotent under redelivery), retries with\nattempts cap, task.completed/task.faile\n[…]\n_BLACKLIST_FAIL_OPEN opt-out)\n\nPlus CHANGELOG.md, py.typed, packaging for the new packages. 60+ new\ntests; full suite green; no migration drift.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: Task primitive + fork-free core (conf namespaces, signals, abst…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T10:15:19Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d2fb399079e22ac954eada51acf3cae147947d31",
"body": "- explicit ack_wait=300 on the durable consumer: handler retries sleep up\n to 14s per message and a batch of 10 is sequential — the 30s default\n would redeliver messages still being processed\n- deterministic Nats-Msg-Id (<event_id>.dlq) on DLQ publishes so a\n redelivery after a failed ack does no\n[…]\ntests need the django_db mark —\n close_old_connections() trips pytest-django's connection guard in\n full-suite runs (order-dependent failures)\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: NATS bus review fixes on top of the JetStream backend",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T08:04:25Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "90d77d6f8109afd4086ddf9706984c18686d6661",
"body": null,
"is_bot": false,
"headline": "wip nats refactoring",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T07:56:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9e0e2e0aaa045ba1d1476d9bad9a927838738d9e",
"body": "…ices\n\n- comm/nats.py: client transport with a dedicated event-loop thread and\n one multiplexed connection per process (nats-py is asyncio-only, call\n sites are sync Django); protocol-level timeouts; NoResponders maps to\n FunctionNotRegistered\n- manage.py serve_functions: provider-side worker sub\n[…]\nnats extra (nats-py>=2.6)\n- removes the connection-per-call failure class entirely and needs no\n FUNCTION_ROUTES — the subject is the discovery\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: NATS request-reply as the recommended Function RPC between serv…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T07:24:03Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d595a5708a9756ec560ca7411925f8295e38c2ea",
"body": "…hardening\n\n- stapel_core.comm: name-addressed Action (emit/on_action) and Function\n (call/@function) primitives; in-process, bus and pluggable dotted-path\n transports (gRPC/NATS slot); pooled HTTP session with connect-only\n retries to survive high call rates; schema validation hooks\n- stapel_cor\n[…]\ning\n- packaging: ship comm/outbox packages, templates and static in wheels;\n Django floor raised to 5.1 (code uses CheckConstraint(condition=))\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: Action/Function comm layer with transactional outbox; security …",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-02T07:10:11Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "187615bf57853fc5551d308ffbb680c8786366c2",
"body": "- Remove IronDataclassSerializer alias (use StapelDataclassSerializer)\n- Remove iron_exception_handler alias (use stapel_exception_handler)\n- Remove IRON_SERVICES / iron_services aliases (use STAPEL_SERVICES)\n- Introduce bus/ module as transport-agnostic replacement for kafka/\n- kafka/__init__.py be\n[…]\n re-exporting from bus\n- Cookie names now configurable via STAPEL_COOKIE_* Django settings\n- django/errors.py: wildcard → explicit re-exports\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor: rename Iron* aliases to Stapel* across the framework",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T20:36:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "56432281769908e71b51b11b88528c058ab20919",
"body": "…eipt\n\nKafkaBus watchdog killed the consumer after HEARTBEAT_STALENESS_S (120s)\nof inactivity because _touch_heartbeat() was only called when a message\nwas received. On low-traffic topics this caused a crash loop every ~2 min.\n\nHeartbeat now reflects poll-loop liveness, not message throughput.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: touch heartbeat on every poll iteration, not only on message rec…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T02:01:35Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "9196596168eca7053fd650d8fc483d9482814db0",
"body": "TestGetOrCreateUserFromJwt tests use @pytest.mark.django_db — without\npytest-django installed, the mark is ignored and the in-memory SQLite\ndatabase is never initialized, causing 'no such table: users' errors.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ci): add pytest-django to test dependencies",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T00:49:54Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d175d08693b351496889f00a0c0ef48581853f87",
"body": "…import\n\npytest tries to import the nearest parent's __init__.py as a package\ninitializer for every test in the package (importtestmodule with\nself.path / \"__init__.py\"). With flat layout, __init__.py sits at the\nrepo root and has relative imports that fail without package context.\n\nAfter pip instal\n[…]\nl source is\nno longer needed. Renaming __init__.py prevents pytest from finding it.\n\nConfirmed 296/296 tests pass locally with this approach.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ci): rename __init__.py before tests to stop pytest package init …",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T00:24:54Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3c50062546619d823c11b4cc50285b8d01d75f34",
"body": "…rsal\n\nIn legacy pytest mode, when tests/ has __init__.py, pytest traverses\nparent directories through __init__.py to determine the package root.\nThe flat package layout (package-dir={\"stapel_core\":\".\"}) places the\nactual package __init__.py at the repo root, which has relative imports\nthat fail whe\n[…]\ncontext.\n\nRemoving tests/__init__.py makes pytest add tests/ to sys.path and\nimport test files as standalone modules, avoiding the traversal.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ci): remove tests/__init__.py to prevent parent __init__.py trave…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T00:15:32Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3561581f6f6079e9798b125bbdd0d30738e5a6e8",
"body": "In legacy pytest mode, when tests/__init__.py exists, pytest traverses\nparent directories looking for the package root and tries to import the\nrepo root's __init__.py as a standalone module. With flat package layout\n(package-dir={\"stapel_core\": \".\"}), this __init__.py has relative\nimports that fail \n[…]\nithout a package context.\n\nimportlib mode bypasses this sys.path traversal, so pytest imports test\nfiles directly without affecting sys.path.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ci): add --import-mode=importlib to prevent __init__.py traversal",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T00:10:09Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e3844064e8c939cd5580e9c896c89c1a7e0ab898",
"body": "The flat package layout (package-dir={\"stapel_core\":\".\"}) places a\ndjango/ directory at the repo root. pytest adds conftest parent dirs\nto sys.path, so `import django` resolved to the local django/ package\ninstead of the installed Django framework — causing CI failures.\n\nFix by removing the repo roo\n[…]\nat the very top of\nconftest.py, before any stapel_core.testing imports run.\n\nAlso revert the cd /tmp workaround in ci.yml (no longer needed).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: remove repo root from sys.path to prevent django/ shadowing Django",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-07-01T00:00:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "07a7da2c72b96f2e610cb1db288ea69c6d632f4c",
"body": "…ango\n\nFlat package layout (package-dir={\"stapel_core\":\".\"}) places django/ at\nrepo root. Python's '' sys.path entry causes `import django` to resolve\nto the local package dir instead of installed Django, breaking all tests.\n\nFix: run pytest from /tmp so CWD has no django/ dir. Revert\n--import-mode=importlib (it broke relative imports in __init__.py).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ci): run pytest from /tmp to avoid django/ shadowing installed Dj…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-30T23:55:02Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "78b8bf3dba880dee57bd657cc3c672af5ee79de4",
"body": "The package uses flat layout (package-dir = {\"stapel_core\" = \".\"}), so\ndjango/ lives at the repo root. pytest adds CWD to sys.path, causing\n`import django` in testing.py to pick up the local django/ package\ndirectory instead of the installed Django framework.\n\n--import-mode=importlib prevents pytest from adding CWD to sys.path.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: add --import-mode=importlib to pytest to fix django/ shadow in CI",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-30T23:39:58Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "de10cbf6fb2c84b0f2c0845b8c776bd94ad0d740",
"body": "…erage\n\n- Consolidate jwt_provider.py → jwt/provider.py (removed duplicate)\n- Extend IronServiceError/IronValidationError aliases\n- Improve openapi schema generation\n- Add test files: test_bus_config, test_captcha_mixin, test_notification_tokens, test_oauth\n- Various minor refactoring and cleanup\n\nAll 296 tests pass\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor: JWT provider consolidation, API layer cleanup, new test cov…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-30T23:07:00Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "6c8a7d6db4fa6a772957b72b69901380b5e6000c",
"body": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "ci: add coverage reporting + Codecov badge to README",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-30T21:51:36Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "6168aff2aba2288acf8f2d5ebd19f2c4f6242f9e",
"body": null,
"is_bot": false,
"headline": "fix: ruff lint cleanup (auto-fix unused imports and style)",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-30T21:37:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c977ffb1ec68f4128359a04e347f309950597d17",
"body": "…ntication\n\n- Add stapel_core.captcha package: CaptchaVerifier ABC, TurnstileVerifier,\n RecaptchaVerifier, HcaptchaVerifier, NoopVerifier, build_verifier factory\n- Add stapel_core.django.captcha: CaptchaMixin DRF serializer mixin,\n get_verifier() reads CAPTCHA_BACKEND/CAPTCHA_SECRET from Django se\n[…]\ncation.py: remove module-level User = get_user_model() (unused,\n caused AppRegistryNotReady when DRF imported the class before Django setup)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: add pluggable captcha system + fix AppRegistryNotReady in authe…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-30T20:53:57Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3730189028f4ed28115d8383e08664035ac16a25",
"body": null,
"is_bot": false,
"headline": "кrfactor structure",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-29T23:43:56Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0185e1bb6ef97250a78ff65d91b876a60198520f",
"body": "Tests: 160 cases across bus, JWT, errors, permissions (0 failures, 0 warnings).\n - tests/conftest.py — configure_django with SQLite+LocMemCache, reset fixtures\n - tests/test_bus.py — Event serialization, MemoryBus publish/subscribe/consume/clear, router\n - tests/test_jwt.py — JWTConfig, JWT\n[…]\n - is_token_near_expiry: utcnow() → now(timezone.utc)\n\npyproject.toml: add [project.optional-dependencies.dev] and [tool.pytest.ini_options]\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: add test suite + fix datetime.utcnow() timezone bug in jwt_handler",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-29T11:26:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "3473071689f07945e7fb8559f6eb6cd7ce6338f4",
"body": "…is client dependency",
"is_bot": false,
"headline": "refactor: TokenBlacklist uses Django cache framework, removes raw Red…",
"author_name": "Victor Pasenchuk",
"author_login": null,
"committed_at": "2026-06-28T16:05:21Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 24,
"commits_last_year": 109,
"latest_release_at": "2026-07-25T20:17:05Z",
"latest_release_tag": "v0.14.2",
"releases_from_tags": true,
"days_since_last_push": 0,
"active_weeks_last_year": 5,
"days_since_latest_release": 0,
"mean_days_between_releases": 1
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": true,
"health_percentage": 100,
"has_issue_template": false,
"has_code_of_conduct": true,
"has_pull_request_template": true
},
"ecosystem": {
"packages": [
{
"name": "stapel-core",
"exists": true,
"license": "MIT",
"keywords": [
"django",
"stapel",
"auth",
"jwt",
"Development Status :: 4 - Beta",
"Framework :: Django",
"Framework :: Django :: 5.2",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Typing :: Typed"
],
"ecosystem": "pypi",
"matches_repo": true,
"registry_url": "https://pypi.org/project/stapel-core/",
"is_deprecated": false,
"latest_version": "0.14.2",
"repository_url": "https://github.com/usestapel/stapel-core",
"versions_count": 20,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": 6794,
"first_published_at": "2026-07-04T00:44:36.034812Z",
"latest_published_at": "2026-07-25T20:19:07.909336Z",
"latest_version_yanked": null,
"days_since_latest_publish": 0
}
]
},
"popularity": {
"forks": 0,
"stars": 1,
"watchers": 0,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": null,
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [
"Makefile"
],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"py.typed"
],
"toolchain_manifests": [],
"largest_source_bytes": 35295,
"source_files_sampled": 347,
"oversized_source_files": 0,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"dependencies": {
"manifests": [
"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": [
"pypi"
],
"dependencies": [
{
"name": "Django",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=5.1"
},
{
"name": "djangorestframework",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=3.14"
},
{
"name": "djangorestframework-dataclasses",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=1.2"
},
{
"name": "drf-spectacular",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.27"
},
{
"name": "django-cors-headers",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=4.3"
},
{
"name": "django-redis",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=5.4"
},
{
"name": "PyJWT",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.8"
},
{
"name": "cryptography",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=41.0"
},
{
"name": "requests",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=2.31"
},
{
"name": "phonenumbers",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=8.13"
}
],
"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": "Pasenchuk",
"commits": 44,
"avatar_url": "https://avatars.githubusercontent.com/u/7511219?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"publish.yml"
],
"has_docs_dir": true,
"linter_configs": [
"ruff.toml"
],
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 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": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"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": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 10,
"reason": "security policy file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 10,
"reason": "0 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "0195be77e753248dbac9381fa4382cada4814459",
"ran_at": "2026-07-25T20:23:38Z",
"aggregate_score": 3.9,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": true,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-25T20:19:11Z",
"oldest_open_prs": [],
"last_merged_pr_at": null,
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/usestapel/stapel-core",
"host": "github.com",
"name": "stapel-core",
"owner": "usestapel"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 54,
"inputs": {
"security": 39,
"vitality": 70,
"community": 49,
"governance": 34,
"engineering": 78
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 70,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 58,
"inputs": {
"commits_last_year": 109,
"human_commit_share": 1,
"days_since_last_push": 0,
"active_weeks_last_year": 5
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "5/52 weeks with commits",
"points": 3.5,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 5
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "109 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 109
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 88,
"inputs": {
"releases_count": 24,
"latest_release_tag": "v0.14.2",
"releases_from_tags": true,
"days_since_latest_release": 0,
"mean_days_between_releases": 1
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "24 version tags (no GitHub releases)",
"points": 16.2,
"status": "partial",
"details": [
{
"code": "version_tags_no_releases",
"params": {
"count": 24
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~1 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 1
}
}
],
"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": 49,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 1,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "1 stars",
"points": 0,
"status": "missed",
"details": [
{
"code": "stars",
"params": {
"count": 1
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "excellent",
"name": "Community health",
"note": null,
"notes": [],
"value": 92,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": true,
"has_issue_template": false,
"has_code_of_conduct": true,
"has_pull_request_template": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 18,
"status": "met",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 13.5,
"status": "met",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 6.3,
"status": "met",
"details": [],
"max_points": 6.3
}
]
},
{
"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": 64,
"inputs": {
"packages": [
"stapel-core"
],
"dependents": null,
"ecosystems": "pypi",
"total_downloads": null,
"monthly_downloads": 6794
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "6,794 downloads/month across pypi",
"points": 51.1,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 6794,
"ecosystems": "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": 10,
"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 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"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": 43,
"inputs": {
"followers": 1,
"owner_type": "Organization",
"is_verified": null,
"owner_login": "usestapel",
"public_repos": 31,
"account_age_days": 31
},
"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 usestapel",
"points": 2.2,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 1,
"login": "usestapel"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "31 public repos, account ~0 yr old",
"points": 11.1,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 31
}
},
{
"code": "account_age_years",
"params": {
"years": 0
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"stapel-core"
],
"ecosystems": "pypi",
"any_deprecated": false,
"min_days_since_publish": 0
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on pypi",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "pypi"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 0 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 0
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "20 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 20
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "good",
"name": "Engineering Quality",
"value": 78,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "good",
"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": 80,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "2 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 2
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": "ruff.toml",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "ruff.toml"
}
}
],
"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": 39,
"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": 39,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 16,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 2,
"scorecard_aggregate": 3.9
},
"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 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"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": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "0 existing vulnerabilities detected",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "moderate",
"name": "AI Readiness",
"value": 59,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "at_risk",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.98,
"agent_instruction_files": [],
"agent_instruction_max_bytes": null
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "no CLAUDE.md / AGENTS.md / editor rules",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_instructions",
"params": {}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "98 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 98,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "good",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 72,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [],
"has_dockerfile": false,
"typed_language": false,
"bootstrap_files": [
"Makefile"
],
"has_devcontainer": false,
"has_linter_config": true,
"typecheck_configs": [
"py.typed"
],
"agent_commit_share": 0.92,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "Makefile",
"points": 18,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Makefile"
}
}
],
"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": "ruff.toml",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "ruff.toml"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "py.typed",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "py.typed"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "92 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 92,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "good",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 82,
"inputs": {
"primary_language": "Python",
"largest_source_bytes": 35295,
"source_files_sampled": 347,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Python with type-check config (py.typed)",
"points": 27,
"status": "partial",
"details": [
{
"code": "typecheck_config_language",
"params": {
"files": "py.typed",
"language": "Python"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/347 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 347,
"oversized": 0
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "at_risk",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": []
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"deps.dev does not index pypi:stapel-core@0.14.2; advisories assessed against the repository dependency graph instead"
],
"report_type": "repository",
"generated_at": "2026-07-25T20:23:43.169712Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/u/usestapel/stapel-core.svg",
"full_name": "usestapel/stapel-core",
"license_state": "standard",
"license_spdx": "MIT"
}