Ownership Manifest & Lease Headers

The ownership manifest tells Weldr which parts of a generated project remain fully managed, which expose safe extension points, and which surfaces are considered fully ejected. It lives at the project root as weldr.ownership.yaml and is evaluated before every regeneration.

Manifest schema

version: ownership/v2
surfaces:
  model:
    mode: managed
    app_model_segments:
      - entities
      - relationships
      - workflows
  db: managed              # drizzle schema + SQL migrations
  auth: managed
  api:
    mode: extended         # generated segments preserved, custom hooks allowed
    hooks:
      - src/api/_hooks/**/*.ts
  actions:
    mode: extended
  automation:
    mode: managed
  domain_logic:
    mode: ejected
    entrypoints:
      - src/domain/**/*.ts
  ui: managed
  ui_pages:
    mode: extended
    app_model_segments:
      - pages
      - navigation
  ui_components:
    mode: extended
    eject_scopes:
      - src/app/**/Custom*.tsx
      - src/components/_custom/**/*
  ui_theme:
    mode: managed
  styling: ejected
  infra: managed
  ci: managed

Surfaces that are omitted default to managed. Structured entries allow extra metadata:

| Field | Meaning | | ------------------- | ------------------------------------------------------------ | | hooks | Glob patterns for additional user-owned files to load. | | entrypoints | Runtime import globs used when a surface is ejected. | | eject_scopes | UI/component globs that Weldr will never overwrite. | | app_model_segments| Which App Model segments the surface governs (e.g. entities, pages). |

Unknown surface keys are ignored and reported as warnings.

Effective state at runtime

loadOwnershipState() resolves the manifest (or produces an all-managed default when missing). The resolved shape is attached to the IR as ir.ownership, so codegen planners and the CLI always operate with the same surface modes. The helper formatOwnershipSummary() powers DX tooling such as weldr doctor.

File leases

Every generated artifact now carries a header describing its surface, ownership mode, and generator:

/** @weldr
  surface: api
  mode: extended
  region-tags: on
  generator: template
  version: ownership/v2
**/

Leases make regeneration deterministic:

  • surface ties the file back to the manifest.
  • mode records whether Weldr may overwrite, merge, or avoid the file.
  • region-tags tracks whether generated/custom segments are expected (used in later phases).
  • generator clarifies which pipeline produced the file (template, llm, or manual).
  • ensureLeaseHeader() inserts or refreshes the header without touching user code, while extractLease() parses existing files for verification.

    Extended regions

    When a surface is set to extended, Weldr emits paired regions in the generated file so that custom code survives regeneration:

    // @weldr:begin crud-order
    // generated code here
    // @weldr:end crud-order
    
    // @custom:begin order-helpers
    // developer-owned code lives here
    // @custom:end order-helpers

    During a subsequent codegen run we only replace the @weldr blocks, leaving the @custom bodies untouched. If a custom block disappears from the latest template we raise a conflict instead of silently deleting user code.

    Contracts

    contracts describe the TypeScript surface a user-owned module must expose once a surface is ejected. Each contract entry specifies a module path relative to the generated workspace and a list of exports Weldr will type-check after regeneration. Example:

    contracts:
      - id: domain.orders
        surface: domain_logic
        module: src/domain/orders.ts
        exports:
          - name: createOrder
            kind: value
            type: '(input: CreateOrderInput) => Promise<Order>'
          - name: Order
            kind: type

    After codegen, Weldr synthesises a temporary TypeScript program that imports each contract and verifies:

  • • The module exists.
  • • The named export (or default export when kind: default) is present.
  • • When a type string is supplied, the exported symbol matches the expected signature in both directions.
  • • Value exports are automatically registered as workflow actions under the ${namespace}.${export} identifier (for example, domainOrders.createOrder).
  • Failures surface as build errors (weldr doctor / weldr sync / weldr contracts check) with the contract id and export name that violated the agreement. This keeps ejected modules honest while letting developers own their implementation details.

    CLI commands

  • weldr doctor — prints the effective ownership table and highlights manifest warnings.
  • weldr leases verify — scans the local workspace, comparing file headers with the recorded manifest and current ownership policy.
  • weldr contracts check — validates contract adapters against developer-owned modules, reporting missing exports and type mismatches.
  • Each command accepts --dir to inspect a specific workspace.

    Defaults & safety nets

  • • Missing manifest ⇒ all surfaces managed (no warnings).
  • • Unknown manifest version ⇒ warning, but the manifest is still processed.
  • • Lease verification checks four failure modes: missing files, missing headers, manifest mismatches, and policy drifts caused by a manifest change without regeneration.
  • This layer is the foundation for the broader partial-ejection roadmap: once leases and ownership metadata are in place, we can introduce region-level merges, contract validation, and CLI workflows without worrying about silent overwrites.