Imports:
  - Types:
      - load_project_config
      - ProjectConfig
      - DepConfig
    From: goga/config
  - Types:
      - ConfigHooks
      - ConfigOverlay
    Usages:
      - checkpoints
    From: goga/config/hooks
  - Types:
      - UsagesHooks
      - UsagesMoment
      - SyncDepOutcome
      - SyncOutcome
      - Completion
    Usages:
      - usages-moments
    From: goga/usages/hooks

Usages:
  convention: .goga/usages/conventions.md
  click: .goga/usages/cooks/click.md
  git: |
    External git binary invoked via subprocess.run (check=True, capture_output=True).
    Set GIT_TERMINAL_PROMPT=0 in the env to suppress interactive prompts. Mock the
    subprocess call in tests per `convention`.

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

  The domain is config-driven: `sync` loads configuration itself via
  `load_project_config` and reads `ProjectConfig`.usages ({group: {dep: DepConfig}} or
  None). All git operations flow through `clone_repository` via the `git` practice;
  mock subprocess calls in tests per `convention`. Use relative imports.
  The operation owns its run-level moments delivered per the
  `usages-moments` practice: the started moment fires once the
  effective configuration is resolved, and the completed moment fires
  on every return path after the start — including an unexpected
  break-off. The moments are notification-only: they wrap the
  operation without participating in it.

---

"sync(force: bool = False, group: str | None = None, dep: str | None = None) -> exit_code: int":
  location: sync.py
  annotations: |
    Config-driven synchronization of cell-level usages from declared git dependencies
    into .goga/usages/<group>/<dep>/.

    `force`: True — clean the synced targets then re-sync the matching declared deps: every
             subtree of .goga/usages/ (except cooks and root *.md) when no filter is set, only
             the `group`/`dep` matches otherwise; False (default) — incremental, skip deps
             whose target dir exists.
    `group`: optional filter — limit the sync to one group name; None (default) → all groups.
             Under `force` the clean removes only this group's subtree.
    `dep`: optional filter — limit the sync to one dep name; None (default) → all deps. `dep`
           without `group` applies across every group; under `force` the clean removes only
           this dep's subtree (under every group when `group` is unset).
    `exit_code`: 0 on success (incl. "nothing to sync"), 1 if any dep failed.

    Algorithm:
    1. Load configuration via `load_project_config` → `ProjectConfig`;
       deliver the config amendment checkpoint per the `checkpoints`
       practice via the `ConfigHooks` checkpoint surface —
       amend_config(config=...) — print the amendment summary lines of
       the `ConfigOverlay` to stderr per the `click` practice (nothing
       when empty), and read the usages declarations of the effective
       configuration. A load or checkpoint failure — ValueError covers
       the hard action, ImportError a broken tool package facade —
       propagates fail-loud at the boundary for the command's wrapper
       to convert; no usages moment fires on this abort
    2. Compose the `UsagesMoment` envelope — the operation kind sync
       with the applied `group`/`dep` filters — and emit the sync-start
       moment per the `usages-moments` practice through the
       `UsagesHooks` checkpoint surface; the started context carries
       the `force` flag and nothing is collected
    3. If ProjectConfig.usages is None → nothing to sync: emit the
       sync-completion moment with the empty outcome set, overall
       success, and the `Completion` marker finished; return 0
    4. usages_root = .goga/usages (relative to CWD)
    5. If `force` → `clean_usages_dir`(usages_root, group, dep) — the clean is scoped by the
       applied filters: no filter → the whole usages root except cooks and root files;
       `group` → the group subtree; `dep` → the dep subtree under every group; both → the
       exact group/dep subtree. Non-matching synced trees stay on disk.
    6. For each group, dep, depcfg (`DepConfig`) in ProjectConfig.usages (insertion order),
       **applying the `group`/`dep` filters (a non-matching name is skipped, not an error —
       a filtered-out dep is absent from the outcomes)**:
       6.1. target = usages_root / group / dep
       6.2. If (not force) and target.exists() → record the dep's
            `SyncDepOutcome` with the `SyncOutcome` value skipped
       6.3. Else: repo = `clone_repository`(depcfg.git, depcfg.ref); try:
            `deploy_usages`(repo, target, depcfg.root); finally: remove the repo temp
            directory; on success record the dep's `SyncDepOutcome` with the
            `SyncOutcome` value synced
       6.4. On per-dep error → log ERROR, record the dep's `SyncDepOutcome` with
            the `SyncOutcome` value failed carrying the credential-free message, set
            overall failure, continue (best-effort)
    7. Emit the sync-completion moment — one `SyncDepOutcome` per matched dep, the run's
       overall success (False when any dep failed), and the `Completion` marker finished
    8. Return exit_code

    Requirements:
    - "synchronized" marker = existence of target dir; dep git/ref changes without force do NOT re-sync
    - The force clean is scoped by the applied `group`/`dep` filters — a subtree not matching
      the filters is preserved on disk; without filters the clean covers the whole usages
      root (`clean_usages_dir` owns the scoping)
    - Clone into a temp dir removed in a finally block
    - deploy receives the dep's optional root verbatim from `DepConfig` (None = walk from
      repo root); `sync` does not resolve or validate root — `deploy_usages` does, against
      the clone
    - A non-matching `group`/`dep` filter value is skipped, never treated as an error; only
      real sync errors on a matching dep set exit_code = 1.
    - The sync-completion moment fires on every return path after the start — the
      nothing-to-do return, the finished return, and the unexpected break-off alike; on a
      break-off the partial outcomes known at the break-off point travel with the overall
      failure, the `Completion` marker crashed, and a credential-free crash reason, and
      the original failure propagates unchanged after the emission
    - A matched dep — a dep of the effective configuration passing the applied filters —
      yields exactly one outcome record; a no-op run (absent usages section or filters
      matching no dep) fires both moments with the empty outcome set
    - The moments wrap the operation without participating in it — output, exit codes, and
      best-effort per-dep isolation are unchanged under any subscription state
    - Every failure fact and diagnostic is credential-free — the same formulation the
      operation logs

    Constraints:
    - Never touch .goga/usages/cooks or root *.md in any mode — filtered or not
      (`clean_usages_dir` owns that)
    - Do not re-sync an existing dep unless force; do not remove a non-matching subtree
      under force
    - Sources are git only (no local-path mode)
    - Do not let the moments alter the operation — no amendment, no veto, no deferral;
      the zone is notification-only

"clean_usages_dir(usages_root: Path, group: str | None = None, dep: str | None = None) -> removed: int":
  location: clean.py
  annotations: |
    Destructive cleanup of .goga/usages/ for force, scoped by the `group`/`dep` filters:
    remove only the matching synced subtrees; keep everything else, cooks, and all files
    directly in usages_root.

    `usages_root`: path to .goga/usages/ (relative to CWD)
    `group`: optional filter — when set, removal covers only this group's subtree (the
             whole group dir, or the single `dep` inside it); None (default) → no group
             narrowing
    `dep`: optional filter — when set, removal covers only this dep name; without `group`
           the dep subtree is removed under every existing group dir; None (default) → no
           dep narrowing
    `removed`: number of directories removed

    Algorithm:
    0. If `usages_root` does not exist → create it (ensure .goga/usages/ exists) and
       return 0 (nothing to clean)
    1. No filters (`group` and `dep` both None) → for each entry in usages_root: skip if
       name equals cooks; if directory → remove it and count; if file → leave untouched
    2. `group` only → remove usages_root/`group` when it is an existing directory; a
       missing or non-directory target is a no-op (0)
    3. `dep` only → for each subdirectory <g> of usages_root except cooks: remove <g>/`dep`
       when it is an existing directory; count one per removal
    4. Both `group` and `dep` → remove usages_root/`group`/`dep` when it is an existing
       directory; a missing or non-directory target is a no-op (0)
    5. Return removed count

    Requirements:
    - When `usages_root` does not exist, create it and return 0 (no-op clean) — keeps the
      routine safe to call on a fresh project and preserves idempotence
    - Preserve the cooks directory verbatim in every mode — including when a filter names
      it (`group` = cooks) or sits inside it; preserve every file in usages_root root
    - Removal targets directories only — a filter naming a root file never touches it

    Constraints:
    - Do NOT remove cooks in any mode, filtered or not
    - Do NOT remove files in usages_root root (only subdirs, except cooks)
    - Do NOT remove a subtree the filters do not match
    - Idempotent

"clone_repository(git: str, ref: str | None) -> repo_path: Path":
  location: clone.py
  annotations: |
    Clone a git repository into a fresh temp dir and return its path. Caller owns cleanup.

    `git`: git repository URL (non-empty)
    `ref`: optional git ref — branch, tag, or commit; None → default branch
    `repo_path`: path to the cloned repo (temp dir; caller must remove it)

    Algorithm:
    1. Create a fresh temporary directory
    2. Suppress interactive prompts per the `git` practice
    3. Clone `git` into the temporary directory via the `git` practice
    4. If `ref` is not None → check out `ref` inside the temporary directory (uniform for branch/tag/commit)
    5. Return the temporary directory path

    Requirements:
    - Use the `git` practice for subprocess invocation

    Constraints:
    - On success, do NOT remove the temp dir here — the caller removes it in a
      finally block (caller owns the returned path only on the success path)
    - On failure (clone/checkout error), DO remove the temp dir here before
      re-raising, so a failed clone never leaks a temp directory
    - Authentication via stock git; no token injection

"deploy_usages(source_repo: Path, target_dir: Path, root: str | None = None) -> count: int":
  location: deploy.py
  annotations: |
    Deploy cell-level usages from a cloned repo into a target dir: discover .usages folders
    under the optional root, lift their contents (drop the .usages name), and copy each to its
    path relative to the root. Placement is deterministic (no flattening).

    `source_repo`: path to the cloned repository root
    `target_dir`: destination .goga/usages/<group>/<dep>/ (created if missing)
    `root`: optional subpath inside `source_repo` from which to walk .usages and against which
            destination paths are computed; None (default) → walk from `source_repo` root
    `count`: number of .usages folders deployed

    Algorithm:
    1. Compute the walk origin: root is None → origin = `source_repo`; otherwise →
       origin = `source_repo` / `root`. Verify origin is an existing directory; if it is
       missing or not a directory → raise an explicit error (walking a missing path or a file
       yields no .usages — do not silently return 0)
    2. Recursively discover every directory named .usages under origin, skipping
       .git/.hg/.svn; record each with its parent's relative path from origin
    3. Create `target_dir` if missing
    4. For each discovered .usages whose parent rel-path from origin is <rel>: copy its
       contents (files + subdirs) into `target_dir`/<rel>/ (create intermediates; preserve
       non-cell directories); drop the .usages segment from every destination path; <rel>
       empty (.usages directly in origin) → copy into `target_dir` root
    5. Return count of deployed .usages folders

    Requirements:
    - Destination path = the .usages parent path relative to the walk origin (root), with the
      .usages segment dropped — verbatim copy, hierarchy preserved including non-cell
      intermediates (root=folder: folder/cell_1/cell_2 → cell_1/cell_2;
      folder/subfolder/cell_1/cell_2 → subfolder/cell_1/cell_2;
      folder/subfolder/cell_1/another_folder/cell_2 → subfolder/cell_1/another_folder/cell_2)
    - root default None → walk from `source_repo` root (the repo-wide default origin)
    - Drop the .usages segment from every destination path
    - Skip .git/.hg/.svn during discovery and copying; copy directories via the standard
      library per `convention`
    - Copy symlinks verbatim — do NOT dereference them. The source is a freshly cloned
      third-party (untrusted) repository; dereferencing its symlinks would copy the contents
      of arbitrary local files/dirs the links point at into the synced output (local-file
      disclosure / aggregation vector). Copying the links themselves never reads those targets.

    Constraints:
    - Placement is deterministic: a single .usages in the repo lands at its origin-relative
      path — at the target root only when it sits directly in the walk origin (no flattening
      applied)
    - Do NOT keep the .usages name in destination
    - Do NOT delete `target_dir` before deploying (sync owns skip; clean owns removal)
    - Do NOT silently succeed when `root` resolves to a missing path or a file — raise

---

Author: Goga
CreatedAt: 27/07/26
Description: |
  Config-driven synchronization of cell-level usages from declared git dependencies
  into .goga/usages/<group>/<dep>/.
