Foundry.Proposals.Proposal (foundry v0.1.1)

Copy Markdown

A proposed change to a target project's codebase. The central resource for Foundry's governance model.

Storage

Proposals are stored as JSON files at .foundry/proposals/prop_<id>.json in the target project's repository. This Ash resource validates and provides typed access to proposal state — Foundry.Proposals.ProposalStore handles reading and writing the JSON files (ADR-015).

The data layer is Ash.DataLayer.Simple — proposals are constructed in-memory from the parsed JSON file. They are not stored in a database.

State Machine

DRAFT → PENDING_REVIEW → APPROVED → APPLIED → COMMITTED

                   
                 REJECTED

Any state → STALE (when blob hashes no longer match — ADR-009) PENDING_REVIEW → SUPERSEDED (when a newer proposal covers the same change)

Approval Mechanics

:sensitive proposals require two distinct approvers (dual approval — ADR-014). :compliance proposals require the compliance_officer and an ADR link. :behavioral proposals require the domain_lead. :structural proposals require any developer; may auto-apply if manifest configured.

Paper Trail and Archival

Proposals are sensitive resources in Foundry's own manifest (they contain diffs of potentially sensitive target platform code). AshPaperTrail and AshArchival are both required (INV-011, INV-012).

ADR

ADR-014 — Proposal Lifecycle. ADR-009 — Concurrent Proposals (blob hash stale detection). ADR-015 — Storage Model.

Summary

Functions

Validates that the keys in the provided input are valid for at least one action on the resource.

Same as input/1, except restricts the keys to values accepted by the action provided.

Types

t()

@type t() :: %Foundry.Proposals.Proposal{
  __lateral_join_source__: term(),
  __meta__: term(),
  __metadata__: term(),
  __order__: term(),
  adr_link: term(),
  aggregates: term(),
  applied_at: term(),
  approval_slot_1: term(),
  approval_slot_2: term(),
  archived_at: term(),
  awaiting_second_approval: term(),
  blob_hashes: term(),
  calculations: term(),
  change_class: term(),
  committed_at: term(),
  diff: term(),
  fully_approved: term(),
  git_commit_sha: term(),
  id: term(),
  impact_analysis: term(),
  inserted_at: term(),
  is_stale: term(),
  lint_result: term(),
  migration_diff: term(),
  operation: term(),
  operation_params: term(),
  paper_trail_versions: term(),
  rejection_reason: term(),
  requester: term(),
  stale_reason: term(),
  state: term(),
  submitted_at: term(),
  superseded_by: term(),
  updated_at: term()
}

Functions

default_short_name()

input(opts)

@spec input(values :: map() | Keyword.t()) :: map() | no_return()

Validates that the keys in the provided input are valid for at least one action on the resource.

Raises a KeyError error at compile time if not. This exists because generally a struct should only ever be created by Ash as a result of a successful action. You should not be creating records manually in code, e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice to be able to validate the keys that are being provided, e.g

Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()

input(opts, action)

@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()

Same as input/1, except restricts the keys to values accepted by the action provided.

primary_key_matches?(left, right)