Spec: docs/design/specs/2026-09-02-artifact-source-whole-file.md
Summary
An artifact's source stops having three meanings and starts having two: the whole file, or
"" because capture was turned off. The byte cap, --artifact-text-max-bytes, and the
text_truncated field all retire. --no-artifact-text stays — opting out of the payload
entirely is a real choice with an unambiguous meaning.
Why
A truncated source reads exactly like a complete small file. Nothing about the value says it
is a prefix, so every consumer has to carry the flag alongside the text to know whether the text
can be trusted — and one that forgets is silently reasoning about the first 256 KB of a file
while believing it has all of it.
The flag cannot carry that meaning cleanly even when it is checked: text_truncated: false
covers both "this is the whole file" and "capture is off, source is empty". It takes
source != "" && !text_truncated to mean "trustworthy", which is a two-field invariant nothing
enforces.
And it buys very little. On microsoft/vscode the cap fired on 32 of 4,953 artifacts — 0.6%.
sha256 and size_bytes were always full-file, so no integrity check ever depended on it.
Why it can't be left half-done
:Artifact is language-neutral by design (can://artifact/<app>/<path>, no Py/J/TS
prefix). A consumer reading that node in a shared database currently gets text_truncated from
two analyzers and not the third — the same divergence that put source on the graph to begin
with.
What each analyzer does
- drop
text_truncated from its artifact model and its graph catalog
- drop
--artifact-text-max-bytes and the truncating branch of text capture
- keep
--no-artifact-text exactly as is
- MAJOR contract bump: a field is removed
python additionally loses its dependency-manifest carve-out from the cap — with no cap there is
no exemption left to state.
Already done
codeanalyzer-typescript shipped this in #117 (c1c27f3) and recorded it in its own repo's
docs/design/specs/2026-08-30-artifact-layer-v130-parity.md §3. No child needed.
Not decided here
Spec §8: whether this shares a MAJOR bump with the prune-scope work (#50 removes _module from
the same catalogs, and two removals in one release should cost one bump), and whether cocoa /
cocoa-ts read the field.
Order
python first (largest simplification, picked up now), then java. Docs follow the last analyzer.
Spec:
docs/design/specs/2026-09-02-artifact-source-whole-file.mdSummary
An artifact's
sourcestops having three meanings and starts having two: the whole file, or""because capture was turned off. The byte cap,--artifact-text-max-bytes, and thetext_truncatedfield all retire.--no-artifact-textstays — opting out of the payloadentirely is a real choice with an unambiguous meaning.
Why
A truncated
sourcereads exactly like a complete small file. Nothing about the value says itis a prefix, so every consumer has to carry the flag alongside the text to know whether the text
can be trusted — and one that forgets is silently reasoning about the first 256 KB of a file
while believing it has all of it.
The flag cannot carry that meaning cleanly even when it is checked:
text_truncated: falsecovers both "this is the whole file" and "capture is off,
sourceis empty". It takessource != "" && !text_truncatedto mean "trustworthy", which is a two-field invariant nothingenforces.
And it buys very little. On
microsoft/vscodethe cap fired on 32 of 4,953 artifacts — 0.6%.sha256andsize_byteswere always full-file, so no integrity check ever depended on it.Why it can't be left half-done
:Artifactis language-neutral by design (can://artifact/<app>/<path>, noPy/J/TSprefix). A consumer reading that node in a shared database currently gets
text_truncatedfromtwo analyzers and not the third — the same divergence that put
sourceon the graph to beginwith.
What each analyzer does
text_truncatedfrom its artifact model and its graph catalog--artifact-text-max-bytesand the truncating branch of text capture--no-artifact-textexactly as ispython additionally loses its
dependency-manifestcarve-out from the cap — with no cap there isno exemption left to state.
Already done
codeanalyzer-typescript shipped this in #117 (
c1c27f3) and recorded it in its own repo'sdocs/design/specs/2026-08-30-artifact-layer-v130-parity.md§3. No child needed.Not decided here
Spec §8: whether this shares a MAJOR bump with the prune-scope work (#50 removes
_modulefromthe same catalogs, and two removals in one release should cost one bump), and whether
cocoa/cocoa-tsread the field.Order
python first (largest simplification, picked up now), then java. Docs follow the last analyzer.