# Architecture

`Weld` is graph-first. Generated files are an output of the graph and plan, not
the primary internal model.

## Core Stages

1. `Weld.Manifest` loads and validates a repo-local manifest.
2. `Weld.Workspace.Discovery` finds projects from manifest globs,
   `blitz_workspace`, or filesystem fallback.
3. `Weld.Workspace` loads each Mix project sequentially and normalizes
   dependencies.
4. `Weld.Graph` stores project nodes, classified edges, publication roles,
   external deps, and violations.
5. `Weld.Plan` resolves one artifact boundary and computes the selected closure.
6. `Weld.Projector` generates the standalone Mix project (routing to
   Weld.Projector.Monolith for monolith artifacts), merged application module
   when needed, and lockfile.
7. `Weld.Verifier` validates the generated project using a mode-specific gate.
8. `Weld.Release` prepares and archives deterministic release bundles.

## Graph Model

Projects are classified independently from publication role.

Classification:

- `:runtime`
- `:tooling`
- `:proof`
- `:ignored`

Publication role:

- `:default`
- `:internal_only`
- `:separate`
- `{:optional, feature_id}`

Internal edges are classified by execution meaning:

- `:runtime`
- `:compile`
- `:test`
- `:docs`
- `:tooling`
- `:dev_only`

Views such as `:package`, `:test`, and `:docs` are computed by filtering those
edge kinds.

External dependencies are also normalized. If a selected workspace project
refers to an external package through `:path`, `:git`, or `:github`, the
manifest must declare the canonical publishable dependency shape. The graph and
plan operate on that normalized external edge, not the local transport detail.
Dependencies without a version requirement are permitted when `opts` includes
`:git` or `:github`.

## Projection Modes

### Package-Projection Mode (default)

Artifacts with `mode: :package_projection` (or no `mode` key) generate a
component-preserving layout under `dist/hex/<package>/`:

```text
dist/hex/<package>/
  mix.exs
  projection.lock.json
  lib/<otp_app>/application.ex
  components/
    apps/core/
    apps/web/
    core/contracts/
  test/
```

This keeps the source graph legible inside the generated package without
turning the output into a second hand-maintained source tree.

### Monolith Mode

Artifacts with `mode: :monolith` merge all selected packages into a single flat
project under `dist/monolith/<package>/`:

```text
dist/monolith/<package>/
  mix.exs
  projection.lock.json
  lib/<otp_app>/application.ex
  lib/
    (merged sources from all selected packages)
  test/
    <package_slug>/
      (tests per selected package)
    support/
      <package_slug>/
        (test support per selected package)
      weld_helpers/
        <slug>_test_helper.exs
  config/
    config.exs
    dev.exs / test.exs / prod.exs
    sources/
      <slug>/config.exs  (sanitized: workspace-app config calls stripped)
    runtime_sources/
      <slug>/config.exs  (original, used at runtime bootstrap)
  priv/
    repo/migrations/          (single-repo layout)
    weld_repos/<slug>/        (multi-repo layout)
```

Key behaviors in monolith mode:

- **File merging**: conflicting source files are renamed with a `<slug>__` prefix.
  A `file_remaps` list in the projection result records all renames.
- **Config sanitization**: static config copies strip workspace-app config calls
  so they do not interfere with the merged config tree. Original files are kept
  under `runtime_sources/` for bootstrap reads at startup.
- **Migration merging**: migrations with the same timestamp prefix are
  re-stamped with a deterministic offset derived from `project_id`, `filename`,
  and sort index. A `.weld_remap.json` records any renames.
- **Test helper synthesis**: each selected package's `test_helper.exs` is parsed,
  `ExUnit.start` calls are extracted and merged, and a root `test/test_helper.exs`
  is generated that dispatches to per-package helper fragments.
- **Explicit source-only test support**: when monolith tests depend on
  non-selected workspace projects, `monolith_opts[:test_support_projects]`
  turns that source-only support set into an explicit manifest contract and the
  copied support code is staged under `test/support/weld_projects/`.
- **Monolith application module**: the generated `Application` module bootstraps
  per-package config at startup using `Config.Reader.read_imports!` before
  starting any OTP application children, and the bootstrap app allowlist is
  derived only from staged bootstrap sources.
- **Test baseline gate**: verification runs each selected package's own test suite
  first, then asserts the monolith test count is at least the baseline sum.

## Constraints

- project probing stays sequential because `Mix.Project.in_project/4` mutates
  global Mix state
- file copying and verification are deterministic
- publish-unsafe external transports must be rewritten through manifest
  dependency declarations
- the generated artifact is normal Mix, not a custom runtime
- monolith mode rejects source files that use `Application.ensure_all_started/1`
  or `Application.app_dir/1` targeting a selected package's OTP app, as these
  assume standalone package identity that is lost in the merge
