Перейти к основному содержимому

Часть III. Алгебра

11. fold — мир как функция от Φ

fold(Φ) → world — чистая операция reduce, применяющая эффекты журнала к начальному пустому состоянию в порядке их времени.

Детерминизм — жёсткое требование: один и тот же Φ даёт одно и то же состояние мира. Это следует из трёх свойств:

  1. α-квантование: каждый эффект описывает минимальный шаг (create entity, replace fields, remove, transition, commit). Последствия эффекта локализованы.
  2. Порядок устойчив: эффекты в Φ упорядочены по времени, и fold применяет их строго в этом порядке.
  3. Без сайд-эффектов в fold: fold — функция над данными, не читает внешние источники.

Из детерминизма следует, что rebuild from scratch — первоклассная операция. Тесты конформных реализаций пересчитывают мир от Φ, чтобы убедиться в интегрировании. Debug workflow использует fold как «машину времени»: проигрывая Φ до момента t, можно посмотреть на мир глазами любого viewer'а в прошлом.

Производные от fold:

  • foldFiltered(Φ, predicate) — пересчёт мира только по релевантным эффектам (для оптимизации больших журналов)
  • foldView(Φ, viewerRole, ontology) — композиция fold и viewer-scoping (см. 14), даёт viewerWorld

Читатели формата (материализации, agent-API, voice) работают не с Φ напрямую, а с миром, полученным fold'ом. Это означает, что журнал остаётся свидетельством, но взаимодействие с пользователем происходит на уровне текущего состояния.

12. Crystallization — артефакт как чистая функция

Кристаллизация — процедура, превращающая набор намерений и онтологию в артефакт (тип данных, описанный в 10). Её сигнатура:

crystallize(intents, ontology, projection, patternBank, features) → artifact

Все пять аргументов — input; артефакт — output. Никаких скрытых состояний, LLM-провайдеров или сетевых обращений. Это ключевое свойство формата: артефакт детерминированно выводится из декларативных данных.

Процедура состоит из шести фаз:

  1. deriveProjections — выводит скелеты проекций из (intents × ontology) по правилам R1–R8: группировка namespace, вывод архетипа, hub-absorption, shape-layer деривация.
  2. mergeProjections — shallow-merge авторских projection поверх derived-скелетов.
  3. assignToSlots — распределяет намерения и данные по слотам согласно архетипу.
  4. matchPatterns — применяет Pattern Bank (см. 13) в matching-режиме; каждый сматченный паттерн становится witness'ом с basis: "pattern-bank".
  5. applyStructuralPatterns — для паттернов с structure.apply — прогоняет apply-функцию, которая мутирует слоты (добавляет секции, меняет layout, переносит элементы). Feature-flag features.structureApply служит emergency kill-switch.
  6. wrapByConfirmation — оборачивает намерения в control-архетипы (confirmDialog, formModal, composerEntry, clickForm, ...).

Детерминизм каждой фазы обязателен. Это делает артефакт:

  • Перегенерируемым — новое preference на проекции → новый артефакт, без потери состояния других частей.
  • Сравниваемым — два артефакта на одинаковых input'ах должны быть equal; diff показывает точное место расхождения.
  • Проверяемым — инварианты формата (см. 23) могут быть подтверждены статически над артефактом.

Author-override через два механизма:

  • projection.patterns — input modifier. Изменяет вход, артефакт остаётся функцией. Preferred way.
  • Slot-override в mergeProjections — output freeze. Автор фиксирует конкретный слот, bypass'а последующие фазы. Потеря: артефакт больше не чистая функция.

Формат рекомендует preference как первый выбор. Slot-override — escape hatch для случаев, когда паттерн принципиально не может быть выражен preference'ом.

13. Pattern Bank — декларативные правила деривации

Pattern Bank — формализованный реестр правил, которые угадывают структуру артефакта из конфигурации входа. Каждый паттерн — запись формата:

{
id: "subcollections",
archetype: "detail",
trigger: { match(projection, ontology, intents) → bool, ... },
structure: {
rationale: "...",
apply?: (slots, context) → mutated slots
},
falsification: { shouldMatch: [...], shouldNotMatch: [...] }
}

Три формы паттерна:

  • Matching-only — паттерн имеет trigger и rationale, но не apply. Роль: аннотация. Сматченный паттерн становится witness'ом, но не меняет слоты. Полезен для фиксации «мы распознали здесь структуру X».
  • Structure.apply — паттерн имеет чистую функцию apply(slots, context) → slots, которая обогащает артефакт. Работает в фазе 5 кристаллизации.
  • Rationale-only — паттерн имеет только объяснительный narrative; используется для документации паттернов, которые ещё не формализованы.

Behavioral vs structural: поведение (monitoring, triage, execution, exploration, configuration) и структура (subcollections, grid-card-layout, hero-create, composer-entry, ...) — ортогональны. Behavioral паттерны классифицируют viewer'а в проекции (что он здесь делает); structural — скелет артефакта (как выглядит). Один артефакт может нести оба вида одновременно.

Falsification framework — обязательная часть каждого стабильного паттерна. Декларация shouldMatch фиксирует примеры, где паттерн должен сработать; shouldNotMatch — где не должен. Это не тесты в коде — это тесты в самом паттерне, запускаемые live-run viewer'ом. Если conformant реализация добавляет новый stable паттерн без falsification-примеров — это некорректная расширение банка.

Witnesses с basis: "pattern-bank" имеют reliability: "rule-based" — самый сильный класс после anchored. Эпистемически они формально выводимы: trigger-функция декларативна, результат детерминирован.

Author-preference через projection.patterns.{enabled, disabled} — способ автора влиять на применение банка без изменения самого банка. Это input-модификатор, не snapshot артефакта: банк остаётся универсальным, preference модифицирует вход кристаллизации.

14. Viewer-scoping — мир и артефакт как функции viewer'а

Один и тот же мир выглядит по-разному для разных ролей — не потому, что рендерер решает что-то скрыть, а потому, что viewerWorld — это отдельный тип данных.

Функция filterWorldForRole(world, viewer, ontology) → viewerWorld применяет row-filter по приоритету:

  1. role.scope — m2m через bridge-сущность. Если роль имеет scope, viewer видит только те target-сущности, для которых bridge связывает viewerField с id viewer'а (опционально с фильтром по statusAllowed).
  2. entity.kind: "reference" — справочные сущности видны всем с правильным role.visibleFields, без ownership-проверки.
  3. entity.ownerField — single-owner semantics: viewer видит сущности, где ownerField совпадает с его id.
  4. none — если ни одного из правил не сработало, сущность не видна (privacy by default).

Base-таксономия роли усиливает viewer-scoping:

  • owner — видит свои сущности, может инициировать все namespace намерений
  • viewer — видит ограниченное подмножество (read-mostly)
  • agent — видит то же, что owner, но каждое намерение проходит через preapproval guard: декларативные лимиты (maxAmount, csvInclude, dailySum, notExpired, active)
  • observer — видит read-only view без привилегий; автоматически конфигурируется role-capability инвариантом

Материализации (pixel, voice, agent API, document) все используют один и тот же filterWorldForRole. Это значит, что viewer-scoping — единый механизм безопасности формата. Нет per-materialization hacks; добавление новой материализации не требует переписывания политик доступа.

Artifact тоже viewer-специфичен: кристаллизация видит только те намерения, которые role.canExecute позволяет, и только те поля, которые role.visibleFields открывает. Артефакт для advisor-роли и investor-роли — два разных артефакта, оба выведены из одной онтологии.