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 is the sole owner of version semantics: the version-form grammar
  and the host-side version consistency check. The grammar, comparison, and
  constraint routines are pure transformers — no I/O, no logging. The check
  routines read one environment variable and the installed-distribution
  metadata of the goga package; user-facing messages go to sys.stderr; click
  is not used. Container or docker invocations never live here — callers hand
  the check already-obtained version strings.

---

"resolve_version(form: str | None) -> spec: str | None":
  location: version.py
  annotations: |
    Sole owner of the four-form version grammar. Maps a version-form string to a
    pip specifier; raises ValueError on operator-prefixed or malformed input.

    `form`: version-form string in one of the four grammar forms, or None when
      the caller's version input is absent
    `spec`: resolved pip specifier to append to the package identifier, or None
      when no specifier should be appended (latest / null marker)

    Algorithm:
    1. If `form` is None or equals the literal string "latest" → return None
       (no specifier — pip selects the newest version under the upgrade request)
    2. If `form` starts with a PEP 440 operator prefix (==, >=, <=, ~=, !=, <,
       >, ===) → raise ValueError (operator-prefixed forms are rejected — this
       routine owns the operator and emits it from the resolved grammar form)
    3. If `form` matches the major x-range pattern "N.x" (exactly one dot, the
       last segment is the literal "x", the first segment is a non-empty
       numeric) → return a compatible-release specifier pinning the lower bound
       on major version N (the form ~=N.0, PEP 440: >=N.0,<(N+1).0)
    4. If `form` matches the minor x-range pattern "N.M.x" (exactly two dots,
       the last segment is the literal "x", the first two segments are
       non-empty numerics) → return a compatible-release specifier pinning the
       lower bound on minor version N.M (the form ~=N.M.0, PEP 440:
       >=N.M.0,<N.(M+1).0). The trailing .0 in ~=N.M.0 is required — ~=N.M
       alone has only a major bound (<(N+1).0) and would NOT pin the minor
       upper limit
    5. If `form` matches the concrete-version pattern "N", "N.M", or "N.M.K"
       (dot-separated non-empty numeric segments, no trailing "x" literal) →
       return an exact-pin specifier (the form ==<form>)
    6. Otherwise → raise ValueError (malformed form)

    Distinguish major x-range ("1.x") from minor x-range ("1.0.x") by counting
    dots — do NOT use prefix matching. The count of dots determines the lower
    bound: one dot pins the major version (form ~=N.0, PEP 440 upper bound
    <(N+1).0), two dots pin the minor version (form ~=N.M.0, PEP 440 upper
    bound <N.(M+1).0). The trailing .0 in the minor case is what actually
    drives the tighter upper bound — do NOT emit ~=N.M (major-only bound).

    Apply `convention` for docstring style and the pure-function discipline
    (no side effects, deterministic output).

    Requirements:
    - The four accepted forms are: "N.x" (major x-range), "N.M.x" (minor
      x-range), "N(.M)?(.K)?" (concrete numeric), "latest"
    - None input is accepted and resolves to None — the marker for an absent
      version input; "latest" is the only canonical no-specifier marker inside
      declarative configuration
    - Every operator-prefixed form (==, >=, <=, ~=, !=, <, >, ===) raises
      ValueError — `resolve_version` owns the operator and emits it from the
      resolved grammar form
    - Pip specifier output is always prefixed with the operator (== or ~=);
      no operator is injected when None is returned

    Constraints:
    - Do NOT accept pre-release, post-release, or local-segment versions
      (1.0.0a1, 1.0.0.post1, 1.0.0+local) — anything richer than the four-form
      grammar is rejected; pip handles richer forms after resolution
    - Do NOT validate that the numeric segments form a real PEP 440 version —
      the routine recognises shape (dot-separated numerics), not existence
    - Do NOT read metadata, log, or perform I/O — it is a pure function

"resolve_relative_spec(base_version: str, patch: bool = False, minor: bool = False) -> spec: str":
  location: version.py
  annotations: |
    Relative version constraint builder: maps an installed version and a
    selected version line to the pip specifier that keeps an upgrade inside
    that line.

    `base_version`: installed version string of the package being upgraded
    `patch`: when True, constrain the target to the latest patch of the current
      minor (line X.Y.*)
    `minor`: when True, constrain the target to the latest release within the
      current major (line X.*)
    `spec`: resolved pip specifier (compatible-release form)

    Algorithm:
    1. Require exactly one of `patch` / `minor`; both set or neither set raises
       ValueError
    2. Reduce `base_version` to its leading release segments: the first numeric
       segment is the major, the optional second numeric segment is the minor;
       anything after them (pre-release, post-release, local, dev tails) is
       discarded
    3. If the base has no leading numeric segments, raise ValueError (the line
       is undeterminable)
    4. When `patch` is set: require the minor segment to exist, otherwise raise
       ValueError; synthesize the minor x-range form "<major>.<minor>.x"
    5. When `minor` is set: synthesize the major x-range form "<major>.x"
    6. Resolve the synthesized form via `resolve_version` and return the
       resulting specifier

    Apply `convention` for docstring style and the pure-function discipline.

    Requirements:
    - Pure function — deterministic, no I/O, no logging
    - The synthesized form is always a valid grammar form, so the pip specifier
      output always carries the compatible-release operator
    - Rich bases are truncated, never rejected: 1.2.0rc1, 1.2.0.post1,
      1.2.0+local, 1.2.1.dev0 all reduce to the 1.2 line

    Constraints:
    - Do not read the installed version here — the caller owns the metadata
      boundary; this routine receives the base as `base_version`
    - Do not validate that segments form a real PEP 440 version — shape
      recognition only, mirroring `resolve_version`
    - Do not compose package identifiers — specifiers only

"compare_versions(host_version: str, image_version: str) -> compatible: bool":
  location: version.py
  annotations: |
    Compare two version strings at the (major, minor) level.

    `host_version`: first version string (release segments, possibly with
      dev/pre/post/local tails)
    `image_version`: second version string (same forms)
    `compatible`: True when the (major, minor) pairs coincide

    Algorithm:
    1. Reduce each argument to its leading release segments: the first
       numeric segment is the major, the optional second numeric segment is
       the minor; everything after them is discarded
    2. Treat a missing minor segment as 0
    3. When an argument has no leading numeric major segment, raise
       ValueError
    4. Return True when both (major, minor) pairs are equal, False
       otherwise — a patch difference does not affect the verdict

    Requirements:
    - Pure function — deterministic, no I/O, no logging
    - Richer tails reduce silently: 1.2.1.dev3, 1.2.0rc1, 1.2.0.post1,
      1.2.0+local all reduce to the 1.2 line

    Constraints:
    - Do not validate that segments form a real released version — shape
      recognition only
    - Do not read metadata or environment — the caller owns the strings

    Apply the `convention` practice for docstring style and the
    pure-function discipline.

"host_goga_version() -> version: str":
  location: version.py
  annotations: |
    Read the version of the goga distribution installed on the host.

    `version`: installed version string of the goga package

    Algorithm:
    1. Read the installed version of the "goga" distribution via the
       standard library importlib.metadata
    2. Return it; when the version cannot be determined, propagate the
       metadata exception unchanged

    Requirements:
    - Single reading point for the host goga version — every consumer of
      the host version goes through this routine

    Constraints:
    - Do not print, log, or terminate — translating the failure into a
      user-facing error belongs to the caller
    - Do not read any other distribution or configuration

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

"version_check_enabled() -> enabled: bool":
  location: version.py
  annotations: |
    Decide whether the host-side version check must run.

    `enabled`: True when the check must run — the probe and the comparison

    Algorithm:
    1. Read the "GOGA_SKIP_VERSION_CHECK" environment variable
    2. Return False only when the value equals the exact string "1"; an
       unset, empty, "0", or any other value returns True

    Requirements:
    - Only the exact value "1" disables the check
    - Companion of `ensure_version_match`: when this predicate returns
      False, the caller skips both the probe and the comparison — one
      gate, one place; `ensure_version_match` runs only on the True path

    Constraints:
    - Do not read any other environment variable; do not print or log

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

"ensure_version_match(image_version: str | None) -> none: None":
  location: version.py
  annotations: |
    Apply the outcome matrix of the host–image version consistency check.

    `image_version`: version string reported for the goga package inside
      the project image, or None when the probe could not determine it

    Algorithm:
    1. Read the host version via `host_goga_version`; when it cannot be
       determined, refuse — a clear message to sys.stderr (no traceback),
       process exit code 1
    2. When `image_version` is None, refuse — a message to sys.stderr
       naming the escape environment variable GOGA_SKIP_VERSION_CHECK,
       process exit code 1
    3. When `image_version` equals "0.0.0", emit a warning to sys.stderr
       and return — an unknown version is not a confirmed mismatch; the
       launch continues
    4. Compare the two versions at the (major, minor) level via
       `compare_versions`; on a difference, refuse — both versions and a
       remediation hint to sys.stderr, process exit code 1
    5. On compatibility, return silently — nothing is printed

    Requirements:
    - Refusal exits the process with code 1 by unwinding the stack, so the
      cleanup blocks of the callers execute; no traceback reaches the user
    - All messages go to sys.stderr only
    - The caller owns the escape decision — this routine runs only when
      the check is enabled

    Constraints:
    - Do not launch containers or invoke docker — version strings arrive
      as arguments
    - Do not print anything on the agreeing path
    - Do not write files

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

---

Author: Goga
CreatedAt: 21/08/26

Description: |
  Leaf cell that owns version semantics: the version-form grammar with
  its pip-specifier transformers, and the host-side version consistency
  check over version strings. No container or docker invocations live
  here.
