# Dependency and Safety

## Why This Exists

The resolver needs a single graph model for explicit dependencies, exported values, imported pipelines, operation-provided dependencies, hooks, safety decorators, and skip propagation. The IR must preserve author intent so those decisions are diagnosable before POSIX emission.

## Producers

- **Parser lowering:** emits dependency, safety, deprecation, export, capture, and future registry-provided decorator roles plus variable references.
- **Resolver:** injects registry dependencies, hooks, transitive safety metadata, and skip decisions.

## Consumers

- **Resolver:** builds the graph, detects cycles, validates missing dependencies, and marks safety gates.
- **Emitter:** generates prereq dispatch, skip checks, export capture, hook calls, and CLI safety flags.
- **Drilling/help:** shows flag provenance, safety requirements, and dependency-derived drill paths.

## Decorator Shape

Pipeline and call nodes embed decorators directly in their payload using `need`, `want`, `safety`, and other decorator roles:

```json
{
  "role": "pipeline",
  "name": "deploy",
  "payload": [
    { "role": "safety", "payload": "remote" },
    { "role": "need", "payload": [
      { "role": "pipeline", "payload": "build" },
      { "role": "var", "payload": "VERSION" }
    ]},
    { "role": "want", "payload": [
      { "role": "pipeline", "payload": "notify" }
    ]},
    {
      "role": "call",
      "payload": [
        { "role": "target", "payload": "infra.deploy" },
        { "role": "args", "payload": [
          { "role": "named", "name": "version", "payload": [{ "role": "var", "payload": "VERSION" }] },
          { "role": "named", "name": "token", "payload": [{ "role": "var", "payload": "DEPLOY_TOKEN" }] }
        ]},
        { "role": "export", "payload": "DEPLOY_URL" }
      ]
    }
  ]
}
```

In OPX:

```
Dp01_ 0.pipeline
nDp01 1.name:string."deploy"
sDp01 1.safety:string."remote"
nD01_ 1.need
pNd01 2.pipeline:string."build"
vNd01 2.var:string."VERSION"
wD01_ 1.want
pWt01 2.pipeline:string."notify"
cD01_ 1.call
tCl01 2.target:string."infra.deploy"
aCl01 2.args
nAr01 3.named
nnA01 4.name:string."version"
vnA01 4.var:string."VERSION"
nAr02 3.named
nnA02 4.name:string."token"
vnA02 4.var:string."DEPLOY_TOKEN"
xCl01 2.export:string."DEPLOY_URL"
```

Future extensions add new decorator roles without widening the pipeline or call schema:

```json
{ "role": "policy", "name": "window", "payload": [
  { "role": "arg", "name": "after", "payload": "09:00" },
  { "role": "arg", "name": "before", "payload": "17:00" }
]}
```

In OPX:

```
Pc01_ 0.policy
nPc01 1.name:string."window"
aP01_ 1.arg
naP01 2.name:string."after"
vaP01 2.value:string."09:00"
aP02_ 1.arg
naP02 2.name:string."before"
vaP02 2.value:string."17:00"
```

## Resolved Graph Metadata

Resolved IR may add graph and skip metadata alongside the lowered form:

```json
{
  "role": "graph",
  "payload": [
    {
      "role": "node",
      "name": "pipelines.deploy",
      "payload": [
        { "role": "need", "payload": [
          { "role": "pipeline", "payload": "build" },
          { "role": "var", "payload": "VERSION" }
        ]},
        { "role": "want", "payload": [
          { "role": "pipeline", "payload": "notify" }
        ]},
        { "role": "safety", "payload": "remote" },
        { "role": "skip", "payload": [
          { "role": "gate", "payload": [
            { "role": "safety", "payload": "remote" },
            { "role": "flag", "payload": "allow-remote" }
          ]},
          { "role": "propagates-to", "payload": "DEPLOY_URL" }
        ]}
      ]
    }
  ]
}
```

In OPX:

```
Gr01_ 0.graph
Nd01_ 1.node
nNd01 2.name:string."pipelines.deploy"
ndN01 2.need
pNn01 3.pipeline:string."build"
vNn01 3.var:string."VERSION"
wtN01 2.want
pNw01 3.pipeline:string."notify"
sfN01 2.safety:string."remote"
skN01 2.skip
gtSk1 3.gate
sfGt1 4.safety:string."remote"
flGt1 4.flag:string."allow-remote"
prSk1 3.propagates-to:string."DEPLOY_URL"
```

## Skip Model

Skip is a semantic resolver/emitter policy derived from decorators and graph edges. It should not be modeled as the literal POSIX sentinel value `__SKIPPED__` in lowered IR.

- `--skip-env` can skip required env values without defaults.
- `--skip-wants` can skip soft dependency decorators.
- Missing `--allow-remote` or `--allow-dangerous` can skip safety-decorated work.
- Skipped work propagates through bindings and references that depend on skipped values.
- Steps that do not consume skipped values continue to run.
- The POSIX emitter may encode skipped values as `__SKIPPED__`, but that is an emission detail.

## Safety Rules

- `remote` and `dangerous` can come from pipeline `safety` roles or registry operation flags.
- Safety is transitive through dependency edges.
- Missing safety opt-ins produce skip behavior, not total pipeline blocking.
- `deprecated` emits warnings at call sites rather than skip behavior.
- Secret references are allowed as dependency/value metadata, but raw secret literals are rejected before graph validation.

## Invariants

- Hard dependencies (`need`) must resolve or produce errors.
- Soft dependencies (`want`) may be skipped by user policy.
- `{ "role": "var", "payload": "NAME" }` dependencies resolve to env constants, exported values, or compile errors.
- Env key conflicts across consumed operations require explicit `env = {}` disambiguation.
- Hook injection is resolver-owned; parser lowering does not synthesize hook steps.
- Decorator roles must be preserved with enough source information to explain graph, skip, and safety decisions.

## Design References

- [build_tiers](../build_tiers.md) tiers 13-15 define resolver graph, env, validation, hooks, and warnings.
- [dependency-constructs](../features/dependency-constructs.md) defines `needs-then`, `has`, and dependency checks.
- [pipeline-markers](../features/pipeline-markers.md) defines safety markers and skip propagation.
- [env-block](../features/env-block.md) defines env conflict and flag provenance rules.
- [drilling](../drilling.md) defines safety flags and skipped dependency behavior.
