Metadata-Version: 2.4
Name: s-corekit
Version: 0.0.4
Summary: ОСНОВАНИЕ китов: ExecutionContext, базовые DTO (SessionRef/Creds/LimitSpec/QuotaInfo), единая иерархия ошибок и чистая классификация состояния доступа (AccessState/AccessVerdict). Только stdlib.
Author: Dmitry
License: MIT
License-File: LICENSE
Keywords: diagnostics,dto,errors,execution-context,redaction,stdlib-only
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# s-corekit — основание экосистемы китов

Значения и чистые правила, на которые опираются остальные пакеты семейства:
контекст исполнения, базовые DTO, единая иерархия ошибок, маскировка секретов и
классификация состояния доступа. **Ноль зависимостей** — только stdlib.

```
     clikit        adapterkit      ветки-оболочки (CLI, адаптеры сервисов)
          \           /
           librarykit             оркестратор (сеть, сессии, браузер)
                |
             corekit              основание (значения и правила)
```

## Установка

```bash
pip install s-corekit
```

Импортируется как `corekit`. Требуется Python 3.11+.

## Быстрый старт

```python
from corekit import ExecutionContext, classify_access, AccessState
from corekit import sanitize_headers, scrub_credentials, RETRYABLE

# 1. Контекст вызова: чей он и под каким профилем идёт.
ctx = ExecutionContext(tenant="acme", profile="main")
ctx.tenant_id, ctx.profile_name          # ('acme', 'main')

# 2. Диагноз по УЛИКЕ, без единого сетевого запроса:
#    200 OK, но конечный URL — страница входа => сессия мертва.
verdict = classify_access(status=200, final_url="https://accounts.google.com/ServiceLogin")
verdict.state                            # AccessState.SESSION_DEAD
verdict.why                              # "сервер оценил куки и увёл на вход (улика: ...)"
verdict.evidence                         # исходная улика, на которой стоит вердикт

# 3. Секреты не утекают в логи.
sanitize_headers({"Authorization": "Bearer ...", "X-Trace": "1"})
# {'authorization': '***', 'x-trace': '1'}
scrub_credentials("socks5://user:pass@127.0.0.1:1080 недоступен")
# 'socks5://***@127.0.0.1:1080 недоступен'

# 4. Одна иерархия ошибок на весь стек + готовый набор «можно повторить».
RETRYABLE                                # (RateLimited, ServerError, TransportError)
```

## Что внутри

| Модуль | Что даёт |
|---|---|
| `corekit.context` | `ExecutionContext` — чей вызов, где его состояние, куда он ходит в сеть. Один тип на экосистему: понимает имена обеих школ (`tenant`/`tenant_id`, `profile`/`profile_name`) и отказывается угадывать при конфликте значений |
| `corekit.dto` | `SessionRef`, `Creds`, `RequestBody` |
| `corekit.limits` | `QuotaScope`, `QuotaInfo`, `LimitSpec` |
| `corekit.enums` | `PaginationMode`, `AuthMode`, `TransportKind` / `RequestExecutionMode` |
| `corekit.errors` | Единая иерархия исключений: `CliError` → `AuthRequired` / `RateLimited` / `Blocked` / `TransportError` / … + кортеж `RETRYABLE` |
| `corekit.redaction` | Маскировка секретов в заголовках, теле и тексте (`sanitize_headers`, `sanitize_body`, `scrub_credentials`) |
| `corekit.diagnosis` | Таксономия причин (`Reason`) и состояние доступа (`AccessState`, `AccessVerdict`, `classify_access`) — диагноз по улике, без сети |

## Правило отбора

В основание попадает сущность, которая **не тянет реализацию**: неизменяемое
значение или чистая функция над текстом/статусом. Всё, у чего есть жизненный
цикл (клиенты, сторы, браузеры, локи), живёт слоем выше — в `s-librarykit`.

Поэтому зависимостей нет и не будет: `dependencies = []` закреплено тестом
`tests/test_stdlib_only.py`. Основание обязано ставиться и туда, где httpx,
pydantic или cryptography поставить нельзя.

## Совместимость с librarykit

Начиная с `s-librarykit` 0.7.6 модули `librarykit.contract`, `librarykit.errors`,
`librarykit.redaction` и `librarykit.diagnosis.*` — тонкие реэкспорты этого
пакета. Они отдают **те же объекты**, а не копии, поэтому `isinstance`, `except`
и сравнение через `is` работают через любой путь импорта:

```python
from librarykit.errors import CliError as ViaLibrarykit
from corekit.errors import CliError as ViaCorekit
assert ViaLibrarykit is ViaCorekit
```

Существующий код, импортирующий эти имена из `librarykit`, менять не нужно.

## Цена импорта (замер, а не обещание)

Python 3.14, Windows, холодный интерпретатор, 3 прогона:

| что | мс |
|---|---|
| пол stdlib (`dataclasses`+`pathlib`+`enum`+`re`+`json`+`datetime`) | 77-85 |
| `import corekit` **поверх пола** | 24-30 |
| `import librarykit` поверх того же пола | 151-162 |
| полный `import corekit` / `import librarykit` | ~105 / ~246 |

Тест меряет цену **над полом**: абсолютное число описывает машину, а не код, и
абсолютный порог пришлось бы задрать так, что приехавший `httpx` (264 мс)
прошёл бы незамеченным.

## Лицензия

MIT — см. [LICENSE](LICENSE).
