Turns model-authored source into {candidate.clj, descriptor.json} and
reports whether it is fit to promote.
mix ptc.materialize MANIFEST --workflow --component ID --out DIR --source authored.clj
mix ptc.materialize MANIFEST --target-mission NAME --component ID --out DIR \
--from-result results/run.json --result-pointer /value/source
mix ptc.materialize MANIFEST --workflow --component ID --out DIR --source authored.clj \
--origin-run-id run-2026-08-03-0001 --accept-widened-effectA model can author a working library inside a run, but a runtime defn dies
at end of run: it is not in the frozen bundle, not covered by a component
source hash, and absent from the mission inventory. This task closes that
loop by making the authored bytes a real component candidate, which a later
run can evaluate through mix ptc run --component-override-descriptor.
Promotion stays an explicit human decision. This task does not promote anything; it makes the decision cheap to reach and well evidenced.
Source acquisition
--source reads raw candidate bytes. --from-result reads a result artifact
written by mix ptc run --output/--private-output and resolves one RFC 6901
JSON pointer to one string, because a result artifact is JSON, not raw Lisp.
A non-string or absent target is refused rather than coerced.
--workflow targets the selected workflow occurrence. --target-mission NAME targets exactly that declared mission; supplying neither or both is
invalid. The target is written into the closed override descriptor.
Publication
--out must not exist. It is created exclusively at mode 0700 with both
files restricted to 0600 before content is written, because a candidate
extracted from a private artifact must not be declassified by publishing it.
A refused candidate leaves nothing behind.
The gate
The candidate is re-acquired through the descriptor just written — the exact path a run takes — and judged on whether it compiles, whether its prompt-visible exports declare a signature and docstring, and whether any export reaches further than the base it replaces.
Every criterion is intrinsic to the candidate or relative to its base. The gate does not check capability grants: real capability names exist only after provider acquisition, so a candidate naming a capability no provider grants passes here and fails at run-time assembly. The gate narrows the distance to that failure; it does not remove it.
A widening is refused unless --accept-widened-effect is given, which is
recorded in the report and in the descriptor's provenance. An override
changes which source compiles, never what compilation permits, so a widening
is not a security hole — but it is a different risk profile and must not pass
silently.
Provenance
--origin-run-id, --origin-prompt-hash, and --origin-authored-at record
who authored the candidate. These are operator-asserted and verified by
nothing: a run id is a claim about origin, not evidence of it. There is no
model-id option, because a descriptor is a published artifact and the raw
model selector must not be published; the authoring model is reachable
through the run id.