Follow-up to #109, filed so the remainder is planned rather than re-derived.
What #109 already shipped
list now carries the fact that a project's dependency list went unread:
- the table heading reads
Package.swift — Swift (dependency list unread) instead of (0 dependencies), in the same words check and the HTML report use;
list --format json gained a per-project dependencies_unread boolean, so an unread list and a genuinely empty one are no longer identical documents.
Only a SwiftPM project can set the bit today: a Package.swift is a program the tool declines to read, so with no readable Package.resolved beside it there is no dependency list at all. A Package.resolved that parses to zero pins leaves the bit false.
Two things were deliberately left out. Both are named here.
(a) list --format json's summary cannot answer "did any manifest go unread"
check --format json answers it in one field: summary.manifests_unread. list's summary object has projects, dependencies and by_ecosystem, and nothing else — so a consumer asking "is any project in this repository unread?" has to iterate projects and reduce dependencies_unread itself. That is the one question a summary exists to answer without iterating.
What deferred it is the naming, and it is a real fork rather than a formality:
projects_unread is consistent with the object it sits in — list's summary counts projects, not manifests — but inconsistent with check, which calls the same count manifests_unread. A consumer reading both documents then meets two names for one fact.
manifests_unread matches check exactly, but introduces a word list's summary uses nowhere else, next to a projects count it would be numerically comparable to and lexically unrelated.
Taking that choice in passing inside #109 would have decided it silently. It should be decided on its own.
Adding the key is additive and stays within dependable.list/v1 under the policy the README and output/list.rs now state.
(b) list --format text emits nothing whatsoever for an unread manifest
This is the sharper of the two, and it is strictly worse than the defect #109 objected to.
--format text writes one tab-separated record per dependency. An unread manifest has no dependencies, so it produces no output at all — not a wrong count, but silence. A script piping list --format text through wc -l cannot distinguish "this project declares nothing" from "this project was never read" from "this path holds no manifest".
It was not changed in passing because the format's contract is deliberate and documented in-code: one record per dependency, fixed arity, the license column emitted unconditionally so the arity does not vary with --licenses. A manifest-level record would break the "every line is a dependency" invariant every consumer of the format relies on, and a sentinel in the name column is a string a real package could legitimately hold. Whatever is done here has to be designed, not appended.
Options worth weighing (not a decision):
- leave
--format text silent and say so in the README, treating stderr's warning as the channel — cheapest, and arguably correct given the contract, but leaves a machine-readable format unable to state the fact;
- a distinct record type on a separate stream or behind a flag;
- a documented manifest-level record with its own leading discriminator column, which changes arity and is therefore a
text-format compatibility event of its own.
Scope
Both halves are crates/dependable/src/output/list.rs plus, for (b), the README's --format text description. Neither touches dependable-core, dependable-fetch, or check.
Follow-up to #109, filed so the remainder is planned rather than re-derived.
What #109 already shipped
listnow carries the fact that a project's dependency list went unread:Package.swift — Swift (dependency list unread)instead of(0 dependencies), in the same wordscheckand the HTML report use;list --format jsongained a per-projectdependencies_unreadboolean, so an unread list and a genuinely empty one are no longer identical documents.Only a SwiftPM project can set the bit today: a
Package.swiftis a program the tool declines to read, so with no readablePackage.resolvedbeside it there is no dependency list at all. APackage.resolvedthat parses to zero pins leaves the bitfalse.Two things were deliberately left out. Both are named here.
(a)
list --format json's summary cannot answer "did any manifest go unread"check --format jsonanswers it in one field:summary.manifests_unread.list's summary object hasprojects,dependenciesandby_ecosystem, and nothing else — so a consumer asking "is any project in this repository unread?" has to iterateprojectsand reducedependencies_unreaditself. That is the one question a summary exists to answer without iterating.What deferred it is the naming, and it is a real fork rather than a formality:
projects_unreadis consistent with the object it sits in —list's summary countsprojects, not manifests — but inconsistent withcheck, which calls the same countmanifests_unread. A consumer reading both documents then meets two names for one fact.manifests_unreadmatchescheckexactly, but introduces a wordlist's summary uses nowhere else, next to aprojectscount it would be numerically comparable to and lexically unrelated.Taking that choice in passing inside #109 would have decided it silently. It should be decided on its own.
Adding the key is additive and stays within
dependable.list/v1under the policy the README andoutput/list.rsnow state.(b)
list --format textemits nothing whatsoever for an unread manifestThis is the sharper of the two, and it is strictly worse than the defect #109 objected to.
--format textwrites one tab-separated record per dependency. An unread manifest has no dependencies, so it produces no output at all — not a wrong count, but silence. A script pipinglist --format textthroughwc -lcannot distinguish "this project declares nothing" from "this project was never read" from "this path holds no manifest".It was not changed in passing because the format's contract is deliberate and documented in-code: one record per dependency, fixed arity, the license column emitted unconditionally so the arity does not vary with
--licenses. A manifest-level record would break the "every line is a dependency" invariant every consumer of the format relies on, and a sentinel in the name column is a string a real package could legitimately hold. Whatever is done here has to be designed, not appended.Options worth weighing (not a decision):
--format textsilent and say so in the README, treating stderr's warning as the channel — cheapest, and arguably correct given the contract, but leaves a machine-readable format unable to state the fact;text-format compatibility event of its own.Scope
Both halves are
crates/dependable/src/output/list.rsplus, for (b), the README's--format textdescription. Neither touchesdependable-core,dependable-fetch, orcheck.