dodil/erp-method

node_modules/.cache/erp-method/v0.1.20/erp/phase/build.md

Phase 4 · Build: compose the bricks, then apply the signed change list

Produce the customer's repo: it depends on the bricks at their tags and holds only what is the customer's. Build only from a signed change list. Back: dodil://erp/build.

Steps

  1. Already ran init at Discover (HR)? Skip to step 2: that folder is the build. Otherwise run one command IN THE PROJECT FOLDER (your current working directory: the customer's repo; never /tmp or a scratch path, or the customer can't find what you built), naming the module(s); no DODIL login needed:
    uvx --from git+https://git.dodil.io/dodil/erp-platform.git@v0.8.2 erp-compose init hr
    
    No uvx? python3 -m venv ~/.erp-compose && ~/.erp-compose/bin/pip install git+https://git.dodil.io/dodil/erp-platform.git@v0.8.2 && ~/.erp-compose/bin/erp-compose init hr. It reads this method's reference.repos and brick_entries, PINS each brick at its tag in requirements.txt, installs them into .venv (erp-platform first), writes compose.yaml and tests/test_composition.py, and runs erp-compose check and the test. It must end with Ready; if it exits non-zero, fix what it names. Never hand-write these files. To read each brick's README.md and AGENTS.md, re-run with --read-copy (bricks/<repo>/).
  2. Configure: apply the change list in order, by depth:
    • depth 1: rows, through the bricks' own use cases (for HR the signed config/hr.calls.yaml, replayed as is; never an INSERT into a brick's table, never an edit under bricks/). Then run erp-compose signoff verify --all: every signed process must say SIGNED.
  3. Extend (depth 2): a new brick in the customer's org from erp-platform/templates/brick-example/ (BRICKS.md) providing the capability, added to compose.yaml. A module no brick covers is a new brick in the same shape (modules/pattern.md §2), its logic generated from ERP_<MODULE>.md, with the story id in each use case's docstring.
  4. Own (depth 3), ONLY for a change the signed BPMN draws: erp-compose own <brick> --reason "<CR>". A wish the diagram does not show (e.g. "escalate to a director" where the brick sends it to HR) is NOT code in this build: record it under Change requests, say so, and take it through dodil://erp/phase/change (propose, sign, then code). Lab, 2026-10-18: a builder edited owned/brick-hr for a step it said "isn't in the diagrams"; the build no longer was the signed one.
  5. The gate (erp-platform v0.8.2, its own step): uvx --from git+https://git.dodil.io/dodil/erp-platform.git@v0.8.2 erp-compose plan compose.yaml REFUSES a module with no signed process (signoff/<module>/<process>.json), a pending change, or a BPMN that no longer matches what was signed; so does migrate. Never route around it: --unsigned "<reason>" is recorded in signoff/<module>.unsigned.json and the bench sees it. From v0.8 init PINS the bricks in requirements.txt (no bricks/; --read-copy to read them); depth 3 is erp-compose own <brick> --reason "<CR>" (copies it to owned/, records the upstream tag).
  6. Show it on localhost (.venv/bin/erp-compose serve compose.yaml, test copy only); tick each change item built in Deviations.

What init writes, for reference (HR, in a folder named acme)

name: acme-hr
version: 0.1.0
tier: 1
bricks:
  - { name: hr, brick: "brick_hr.application.use_cases:HR", version: 0.5.0 }
  - { name: bp, brick: "brick_bp.application.use_cases:BP", version: 0.3.1, process_view: "none: master data only, no lifecycle to sign" }

Done when

  • erp-compose check is clean and tests/test_composition.py passes.
  • Every change item is built, and the regenerated process view matches the signed one.
  • No brick clone differs from its tag except a declared fork.
  • erp-compose plan passes the gate with no --unsigned.

Next: dodil://erp/phase/test