punix why¶
Print a binding's resolved value + its provenance chain: the (file, line, source) history of each contribution 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. -
An f-string is composed in the pure layer, so
whyprints the composed value and the chain of the reference it read:$ punix why mytree ripgrep.url ripgrep.url = 'https://github.com/BurntSushi/ripgrep/archive/refs/tags/14.1.1.tar.gz' winner: mytree/official/ripgrep.pcl:3 [optionDefault] (ripgrep)The URL is derived from
version, sopunix why mytree ripgrep.versionis where an override shows up. - Exit codes: 0 / 1 / 2 (same ascheck).
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.