Imports:
  - Types:
      - HookRegistry
      - wrap_context
      - build_hook_arguments
      - declared_actions
    Usages:
      - per-tool-delivery
      - registering-hooks
    From: goga/hooks

Usages:
  convention: .goga/usages/conventions.md

Annotations: |
  The `convention` practice is used for:
  - Working with the codebase
  - Organizing the REPL development cycle
  - Debugging and testing
  - Organizing the test infrastructure
  - Understanding the general principles and rules of
  development and testing in the project

  This cell owns the hooks zone of the contract domain: the per-cell
  read view of the comparison facts, the per-tool contribution model
  with its type-addressed unit commit, and the checkpoint surface that
  delivers the contract amendment over the platform facade. One
  registry per run carries every checkpoint of a command — the
  checkpoints never multiply the package enumeration. Every context is
  built from the operation data the caller passes — no configuration,
  git, or file reads happen here, and the extended domain is not
  imported. The amendment action is hard: the first failing hook of
  the delivery walk — a crashed hook, a structurally malformed
  contribution, or a contribution addressed to a type the cell does
  not declare — stops the command with a clean error naming the tool,
  the action, and the failing cell path, and the offending type name
  for a bad address; the tool's whole contribution is discarded.
  Tools are mutually blind — every delivered view reads the authored
  comparison facts only, never another tool's contribution; each
  tool's contribution commits as a unit, in enumeration order, per
  cell. The contributions live in memory for the current run — the
  comparison output is composed fresh from the caller's data.
  Use the `per-tool-delivery` practice for the staged delivery loop of
  the amendment checkpoint — its loop skeleton, primitives, and
  tool-grouped commit apply as written.
  Use the `registering-hooks` practice for the hook signature and the
  failure handling behind the checkpoint.
  Use relative imports.

---

"CellFacts(path: str, types: list[TypeFacts])":
  location: facts.py
  annotations: |
    The comparison facts of one cell — the per-cell read view
    delivered to a subscribed hook.

    `path`: the normalized cell path
    `types`: the comparison facts of each declared type of the cell

    Apply the `convention` practice for the data-model rules and
    intra-package imports.

    Requirements:
    - Pure facts — the constructing operation passes resolved values;
      nothing is read here
    - Authored projection only — the declared and extracted forms
      exactly as the caller's comparison composes them; identical for
      every tool
    - One shape for every implementation language — no per-language
      projection
  properties:
    "path -> str": |
      The normalized cell path.
    "types -> list[TypeFacts]": |
      The comparison facts of each declared type of the cell.

"TypeFacts(name: str, signature: FormFacts, properties: list[MemberFacts], methods: list[MemberFacts])":
  location: facts.py
  annotations: |
    The comparison facts of one declared type — the name with the
    compared signature and the compared members.

    `name`: the declared type name
    `signature`: the compared signature of the type
    `properties`: the compared property members — empty for a routine
    `methods`: the compared method members — empty for a routine

    Apply the `convention` practice for the data-model rules and
    intra-package imports.

    Requirements:
    - Pure data — constructed by the caller from its own comparison
      values
  properties:
    "name -> str": |
      The declared type name.
    "signature -> FormFacts": |
      The compared signature of the type.
    "properties -> list[MemberFacts]": |
      The compared property members — empty for a routine.
    "methods -> list[MemberFacts]": |
      The compared method members — empty for a routine.

"FormFacts(codemanifest: str, implementation: str | None)":
  location: facts.py
  annotations: |
    One compared form — the declared string and its extracted
    counterpart, including an absent counterpart.

    `codemanifest`: the declared form of the CODEMANIFEST
    `implementation`: the extracted counterpart — absent when the
                      implementation carries none

    Apply the `convention` practice for the data-model rules and
    intra-package imports.

    Requirements:
    - Pure strings only — the language-agnostic shape carries no
      parsed structures
  properties:
    "codemanifest -> str": |
      The declared form of the CODEMANIFEST.
    "implementation -> str | None": |
      The extracted counterpart — absent when the implementation
      carries none.

"MemberFacts(name: str, form: FormFacts)":
  location: facts.py
  annotations: |
    The compared form of one named member — a property or a method.

    `name`: the declared member name
    `form`: the compared form of the member

    Apply the `convention` practice for the data-model rules and
    intra-package imports.

    Requirements:
    - Pure data — constructed by the caller from its own comparison
      values
  properties:
    "name -> str": |
      The declared member name.
    "form -> FormFacts": |
      The compared form of the member.

"ContractAmendment(cell: CellFacts)":
  location: amendments.py
  annotations: |
    The read-and-contribute view of one tool for one cell — the
    delivered facts of the amendment checkpoint and the buffer of
    this tool's type-addressed contributions.

    `cell`: the comparison facts of the cell being amended —
            read-only and identical for every tool

    Apply the `convention` practice for the data-model rules and
    intra-package imports.
    Use the `registering-hooks` practice for the hook signature that
    receives this view.

    Requirements:
    - The reads deliver the comparison facts — a tool never sees
      another tool's contribution
    - The buffered contributions belong to this tool alone
  properties:
    "cell -> CellFacts": |
      The comparison facts of the cell; read-only for the receiving
      hook.
  methods:
    "contribute(facts: dict[str, dict[str, object]])": |
      Buffer one type-addressed contribution of this tool.

      `facts`: the type-addressed mapping — declared type name to
               the tool's fact mapping for that type

      Requirements:
      - The call buffers into the buffer of this tool alone and
        changes nothing until the delivery commits it
      - The buffer merges key-wise — for one type, a later write
        replaces an earlier one on fact-name conflict; a repeated
        type address merges its facts
      - An empty outer mapping contributes nothing

      Constraints:
      - Do not cancel, redirect, or defer the operation — a
        contribution extends the addressed type nodes' tools areas
        only

"ToolContribution(tool: str, facts: dict[str, dict[str, object]])":
  location: overlay.py
  annotations: |
    The committed contribution of one tool for one cell — the pairing
    of the tool identity with its type-addressed fact mappings.

    `tool`: the tool identity assigned by the platform
    `facts`: the committed type-addressed contributions of the tool

    Apply the `convention` practice for the data-model rules and
    intra-package imports.

    Requirements:
    - Pure data — constructed by the checkpoint delivery alone
  properties:
    "tool -> str": |
      The tool identity assigned by the platform.
    "facts -> dict[str, dict[str, object]]": |
      The committed type-addressed contributions of the tool.

"merge_type_contributions(contributions: list[ToolContribution]) -> tools: dict[str, dict[str, dict[str, object]]]":
  location: overlay.py
  annotations: |
    The deterministic per-type tools-area composition — the mapping
    of each addressed type name to its tools area, built from the
    committed contributions.

    `contributions`: the committed contributions in enumeration order
    `tools`: the tools area per addressed type name — empty when
             nothing contributed

    Apply the `convention` practice for docstring style and
    intra-package imports.

    Algorithm:
    1. Take the contributions in enumeration order
    2. Skip a contribution whose mapping is empty — a tool exists on
       a type iff that tool wrote at least one fact for that type
    3. For each type name the contribution addresses, place the
       tool's fact mapping under the tool identity inside that type's
       area
    4. A type name absent from every committed contribution is
       absent from the result
    5. Return the composed mapping — empty when every contribution
       was empty or none committed

    Requirements:
    - Deterministic — the same contributions give the same mapping
    - Pure — the inputs stay unmutated; the result is a new mapping
    - Structural validation is not here — it happened at the tool
      commit point of the delivery

    Constraints:
    - Do not read or write the filesystem
    - Do not mutate `contributions` or their maps

"ContractHooks()":
  location: events.py
  annotations: |
    The checkpoint surface of the contract domain — the
    contract-amendment delivery over the platform facade.

    Apply the `convention` practice for the code style and
    intra-package imports.
    Use the `per-tool-delivery` practice for the staged delivery loop
    of the amendment checkpoint.
    Use the `registering-hooks` practice for the registration contract
    behind the checkpoint.

    Requirements:
    - Cheap construction — no enumeration and no imports happen at
      construction
    - One `HookRegistry` per run carries every checkpoint of a
      command — the assembly runs once per run whatever the number
      of checkpoints
    - Every context is built from the values the caller passes — no
      configuration, git, or file reads happen at the checkpoint
  methods:
    "amend_contract(cell: CellFacts) -> tools: dict[str, dict[str, dict[str, object]]]": |
      Deliver the contract-amendment checkpoint for one cell and
      return the tools area per addressed type.

      `cell`: the comparison facts of the cell — operation data
              handed over by the calling command
      `tools`: the tools area per addressed type name — empty when
               nothing contributed

      Use the `per-tool-delivery` practice for the delivery loop.

      Algorithm:
      1. Resolve the address domain="contract", action="amend_contract"
         against `declared_actions`
      2. Walk the subscriptions of the address per tool in
         enumeration order: build the tool's `ContractAmendment` view
         over the delivered facts — every tool reads the same `cell` —
         wrap it via `wrap_context`, project the call arguments via
         `build_hook_arguments` with the tool's own context, and call
         each hook of the tool
      3. A tool whose every hook returned without raising passes the
         structural check of its merged buffer — a payload not
         representable on the type nodes (a non-mapping payload,
         non-string keys, non-serializable values, or an empty
         mapping at any nesting level) or an address naming a type
         the cell does not declare is the same hard failure as a
         crashed hook
      4. A passing tool commits as one `ToolContribution` — what
         commits is an owned copy of the validated buffer, so a
         container the tool retains and mutates at a later cell never
         reaches the committed area; an empty merged buffer commits
         nothing
      5. A hard failure stops the delivery at the first failure in
         the walk — a clean error naming the tool, the action, and
         the failing cell path, and the offending type name for a
         bad address; the tool's contribution is discarded
      6. Compose the tools areas of the committed contributions via
         `merge_type_contributions` and return them

      Requirements:
      - The commit granularity is the tool — a tool's whole
        contribution commits only after every hook of the tool
        succeeds and the merged buffer is structurally representable
        and fully addressed to declared types
      - An address without subscriptions returns an empty mapping —
        the delivery is unobservable, the caller's output stays
        byte-identical
      - With no tool packages installed the checkpoint returns an
        empty mapping

      Constraints:
      - Do not apply any contribution outside the single composition
        after the walk
      - Do not skip a subscriber of the address
      - Do not read configuration, git, or the filesystem at the
        checkpoint
      - Do not print — the caller owns all output

---

Author: Goga
CreatedAt: 29/09/26
Description: |
  Owner of the contract domain hooks zone — the per-cell read view, the
  per-tool contribution model, and the checkpoint surface over the
  hooks platform.
