Skip to content
docsv0.19.0

DescentCertificate

The evidence that lets a descent lower a ceiling, and the proof of where that evidence came from. greenhouse decisions/0045 decided a descent is earned by being CERTIFIED, never declared; decisions/0050 gave the certificate a shape a runtime can check on its own; decisions/0051 added the only thing those two could not buy — provenance. WHAT EACH PART ANSWERS, and nobody has to be trusted for any of it: · `operation` + `handlerSha256` is this about the very call being made, and the very code about to run? Either alone lets a certificate slide. · `predicate` was it earned by THESE arguments? `dry=true` and `force=true` on one handler are two different descents. · `to` did the evidence justify THIS destination? · `covers` which axes did a control actually demonstrate? Never «certified» flat: `evidence/0245` showed an honest disk certificate being presentable as proof about the network. · `signature` did this exact payload come from the certifier, or from a text editor? `evidence/0249` deleted the artifact, rewrote it by hand with a digest computed by `sed | sha256sum`, and the ceiling came down. WHAT THE SIGNATURE DOES NOT DO. It adds no criterion. A signed certificate covering only `mutation` still cannot lower `authority`, because the criterion lives in the verifier and stays there. And it proves PROVENANCE, not INDEPENDENCE: whoever controls the repository and the pipeline is still one actor. decisions/0051 declares that residue rather than hiding it. THE PUBLIC KEY MUST NOT COME FROM THE ARTIFACT. It belongs where the operation is declared — reviewed code — because a key read from the same file as the signature lets a forger swap both and sign their own lie, which is the exact attack this class exists to stop.

DescentCertificate::__construct()

public function __construct(string $verifier, string $operation, array $predicate, array $covers, Milpa\Command\Effect\EffectProfile $to, ?string $handlerSha256 = null, array $envelope = [], ?string $verdict = null, ?string $signature = null, ?string $verifierPublicKey = null):

Parameters

Parameters of __construct()
NameTypeDescription
$verifierstringwho produced it, with its version
$operationstringthe operation this evidence is about
$predicatearray<string, mixed>the exact arguments exercised, as `[argument => value]`
$coverslist<string>the EffectProfile axes a control demonstrated
$toEffectProfilethe reduced ceiling this evidence justified
$handlerSha256(string | null)the digest of the handler body that was watched
$envelopearray<string, mixed>what the instruments saw and where they are blind
$verdict(string | null)what the verifier concluded, in its own words
$signature(string | null)base64 detached signature over {@see canonicalPayload()}
$verifierPublicKey(string | null)base64 ed25519 key of the recognised certifier

DescentCertificate::canonicalPayload()

public function canonicalPayload(): string

The exact bytes that are signed and verified — never «an equivalent JSON». Two serialisations of one payload would be two signatures, and the ambiguity is the bug: the certifier and the runtime must agree byte for byte. So the order is fixed here, in one place, and every value is rendered explicitly rather than left to whatever the encoder felt like.

DescentCertificate::signedWith()

public function signedWith(string $secretKey): self

The same certificate, carrying a detached signature over its canonical bytes.

Parameters

Parameters of signedWith()
NameTypeDescription
$secretKeystring

DescentCertificate::signedByItsVerifier()

public function signedByItsVerifier(): bool

Did THIS payload come from the certifier this deployment recognises? Everything missing or malformed answers no. An unsigned certificate is not a certificate with an open question — it is a file someone wrote.

DescentCertificate::speaksAbout()

public function speaksAbout(Milpa\Command\Effect\Descent $descent, ?Milpa\Command\Effect\CallSubject $subject): bool

Does this certificate speak about the very call being made — the operation AND its arguments?

Parameters

Parameters of speaksAbout()
NameTypeDescription
$descentMilpa\Command\Effect\Descent
$subject?Milpa\Command\Effect\CallSubject

DescentCertificate::watched()

public function watched(?string $handlerDigest): bool

Is this still the handler the verifier watched? A caller that cannot say which handler is about to run gets `false`, not the benefit of the doubt: not being able to look is not the same as having looked and found nothing.

Parameters

Parameters of watched()
NameTypeDescription
$handlerDigest?string

DescentCertificate::coversAll()

public function coversAll(array $loweredAxes): bool

Did a control demonstrate every axis this descent actually lowers? Axes that do not move need no evidence — the claim is only as wide as the reduction. An axis that comes down without a control behind it is a claim wider than its proof, and it takes the whole descent with it.

Parameters

Parameters of coversAll()
NameTypeDescription
$loweredAxeslist<string>