punix why¶
Print a binding's resolved value + its provenance chain — the per- contribution (file, line, source) history that produced it.
Synopsis¶
TARGET is Module.field syntax — e.g. Db.host, Curl.version.
Output¶
$ punix why stack.pcl Db.host
host = "db.prod.example"
chain:
base.pcl:8:3 Db.host = "localhost" (Db)
prod.pcl:14:3 Db.host = "db.prod.example" (scenario Prod) ← winner
The chain shows every contribution to Db.host in deploy order, with locations and the source (Db for the base module, scenario Prod for the override). The last line is the winner.
Why this exists¶
Every field's value MUST be explainable offline. After a deploy, "why is this Caddyfile saying forge.example.com?" reads the provenance chain from provenance.json and traces every contribution back to its file:line.
punix why is the interactive form of that — answer the same question without grepping JSON.
Notes¶
- Provenance is CIA-stable: the winner is order-independent; only the file:line citations depend on source order. Two permuted source trees produce the same winner, different
whyline numbers — that's correct by design — a property the conformance suite pins. - Secret values are excluded from provenance.
{from_env=…}appears in the chain by its reference string, never the resolved value. - Exit codes: 0 / 1 / 2 (same as
check).
Examples¶
# Why does the API service bind to this port?
punix why stack.pcl Api.port
# Trace a cross-module ref
punix why stack.pcl ApiService.dbHost # → traces Api.host → Db.host
Related¶
- Modules — how cross-module refs resolve.
- Concepts: content-addressing — what CIA stability buys.