Proposal: Add Formula and Module modes to llar list
Summary
Add a read-only llar list [module] command with two object modes. Formula mode is the default and returns ordered Formula ranges plus Matrix metadata. The -m flag switches to Module mode and returns known upstream versions plus the static dependency table from versions.json.
The command does not accept module@version. Concrete version, matrix, dynamically resolved dependencies, and result data remain owned by llar make --json and llar install --json.
Motivation
LLARHub needs catalog data without parsing Formula source or invoking builds:
- Formula data: ordered
fromVer boundaries and Formula Matrix metadata.
- Module data: module path, all known upstream versions in module-defined order, and static version-keyed dependency pins.
Formula already owns a Matrix structure with Require, Options, and DefaultOptions. Reusing it avoids separate and overlapping JSON contracts for defaults, options, and filter-related capability data.
Goals
- List Formula ranges and Matrix metadata by default.
- List Module metadata only with
-m.
- Order ranges and upstream versions with the module comparator, without assuming semantic versions.
- Preserve the
versions.json dependency-table shape and its static meaning.
- Support the current local Formula checkout and explicit module arguments.
- Remain read-only and suitable for automation.
Out of Scope
module@version queries.
- Concrete version and matrix resolution.
- Running Formula
filter, onRequire, or MVS for dependency output.
- Defining how complete future Matrix requirement and option domains are derived.
- Artifact, cache, local/cloud availability, output-directory, or build-metadata listing.
- Module patterns, recursive
..., or all.
- A separate
llar inspect command.
- The LLARHub Action or final website
data.json schema.
Formula Mode
Formula mode is the default:
llar list --json
llar list google/highway --json
llar list ./google/highway --json
It emits one module-level object:
{
"path": "google/highway",
"ranges": [
"1.4.0"
],
"formulas": [
{
"fromVer": "1.4.0",
"matrix": {
"require": {},
"options": {
"fPIC": ["ON"],
"shared": ["OFF"],
"with_test": ["OFF"]
},
"defaultOptions": {
"fPIC": ["ON"],
"shared": ["OFF"],
"with_test": ["OFF"]
}
}
}
]
}
A module with multiple ranges has the same shape:
{
"path": "example/library",
"ranges": [
"v1.4",
"v1.2"
],
"formulas": [
{
"fromVer": "v1.4",
"matrix": {
"require": {},
"options": {
"shared": ["OFF"]
},
"defaultOptions": {
"shared": ["OFF"]
}
}
},
{
"fromVer": "v1.2",
"matrix": {
"require": {},
"options": {
"shared": ["ON"]
},
"defaultOptions": {
"shared": ["ON"]
}
}
}
]
}
Rules:
ranges contains every Formula fromVer, ordered highest to lowest by the module comparator.
formulas uses the same order and formulas[i].fromVer == ranges[i].
matrix reuses the Formula Matrix shape.
matrix.require, matrix.options, and matrix.defaultOptions are map[string][]string.
- Existing Formula defaults are represented in both
matrix.options and matrix.defaultOptions, matching the current Defaults behavior that initializes the active option selections and their defaults.
- Version 1 emits an empty
require object when the Formula declares no target requirements.
- Formula
filter is not a separate JSON field. Future capability data uses the Matrix structure.
ranges is a boundary list, not synthesized {min,max} objects.
Module Mode
The -m flag switches to Module mode:
llar list -m --json
llar list -m google/highway --json
llar list -m ./google/highway --json
{
"path": "google/highway",
"versions": [
"v0.7.0",
"0.11.0",
"0.11.1",
"1.4.0"
],
"deps": {}
}
Rules:
versions contains every known upstream tag, preserving original strings and ordered lowest to highest by the module comparator.
deps exactly preserves the version-keyed versions.json shape.
deps means static declarations and pins only.
- Module mode does not execute Formula hooks, inject a matrix, or run MVS.
deps must not be interpreted as the effective dependency graph for a concrete version and matrix.
Module Selection
With no module argument, the command walks from the working directory to the nearest versions.json and uses that local module.
An explicit local path selects that Formula checkout. An explicit module path selects that named module. A module@version argument is invalid in both modes.
Output And Errors
--json writes one JSON object per selected module to standard output. Diagnostics go to standard error. A failed query exits non-zero and must not emit a partial object.
Without --json, the command may render the same selected mode for humans. Human-readable output is not the automation contract.
Missing maps and arrays in the contract are encoded as {} and [], never null.
The command returns an error for an invalid module path, module@version, missing or invalid versions.json, Formula loading failure, comparator failure, or upstream version-query failure.
The command must not build, install, test, download artifacts, resolve dynamic dependencies, or mutate artifact-cache state.
Static And Resolved Dependencies
The two deps contracts remain distinct:
llar list -m deps = versions.json static declarations and pins
make/install deps = concrete version + matrix resolution result
For a concrete resolution, LLAR selects the Formula for the requested source version, injects the matrix, runs filter and onRequire, uses versions.json for pins or fallback, and then runs MVS. llar list performs none of those steps for deps.
Architecture Boundary
The module loader owns module paths, Formula discovery, custom version comparison, Matrix metadata, and dependency resolution. Formula mode exposes Formula boundaries and Matrix data. Module mode exposes upstream versions and the static versions.json table. The CLI owns mode selection, argument parsing, and rendering. LLARHub owns combining these facts with GitHub metadata and CI results.
Implementation must expose only the minimum internal data required by the CLI. It must not expose interpreted Formula callbacks, build contexts, cache internals, or resolver policy as a public API.
Compatibility
This proposal is additive. It changes no existing make, install, test, Formula DSL, versions.json, cache, artifact, or comparator behavior.
Alternatives Considered
Separate defaults, options, and filter fields
Rejected because Formula already owns Matrix{Require, Options, DefaultOptions}. Reusing Matrix provides one consistent contract.
One Formula JSON object per Formula
Rejected because callers need one module-level catalog containing the ordered ranges and corresponding Formula records.
Synthesized {min,max} ranges
Rejected because Formula selection is defined by ordered fromVer boundaries and the last Formula has no finite upper bound.
Treat static dependencies as effective dependencies
Rejected because onRequire may change dependencies for a concrete source version and matrix.
Separate llar inspect
Rejected because default Formula mode and explicit -m Module mode already provide the required boundary.
Include artifact availability
Rejected because make --json and install --json own result data. Read-only artifact inventory requires a separate storage-enumeration design.
Acceptance Criteria
llar list <module> --json emits one Formula catalog object with only path, ordered ranges, and same-order formulas containing fromVer and matrix.
- Every Formula Matrix contains
require, options, and defaultOptions maps shaped as map[string][]string.
- Existing Formula defaults appear in both
matrix.options and matrix.defaultOptions.
llar list -m <module> --json emits only path, comparator-ordered versions, and the unchanged static deps table.
- No-argument queries resolve the current module through the nearest
versions.json.
module@version is rejected in both modes.
- Empty maps and arrays are
{} and [], not null.
- Neither mode executes a build, install, test, artifact download, dynamic dependency resolution, or cache mutation.
Proposal: Add Formula and Module modes to
llar listSummary
Add a read-only
llar list [module]command with two object modes. Formula mode is the default and returns ordered Formula ranges plus Matrix metadata. The-mflag switches to Module mode and returns known upstream versions plus the static dependency table fromversions.json.The command does not accept
module@version. Concrete version, matrix, dynamically resolved dependencies, and result data remain owned byllar make --jsonandllar install --json.Motivation
LLARHub needs catalog data without parsing Formula source or invoking builds:
fromVerboundaries and Formula Matrix metadata.Formula already owns a Matrix structure with
Require,Options, andDefaultOptions. Reusing it avoids separate and overlapping JSON contracts for defaults, options, and filter-related capability data.Goals
-m.versions.jsondependency-table shape and its static meaning.Out of Scope
module@versionqueries.filter,onRequire, or MVS for dependency output...., orall.llar inspectcommand.data.jsonschema.Formula Mode
Formula mode is the default:
It emits one module-level object:
{ "path": "google/highway", "ranges": [ "1.4.0" ], "formulas": [ { "fromVer": "1.4.0", "matrix": { "require": {}, "options": { "fPIC": ["ON"], "shared": ["OFF"], "with_test": ["OFF"] }, "defaultOptions": { "fPIC": ["ON"], "shared": ["OFF"], "with_test": ["OFF"] } } } ] }A module with multiple ranges has the same shape:
{ "path": "example/library", "ranges": [ "v1.4", "v1.2" ], "formulas": [ { "fromVer": "v1.4", "matrix": { "require": {}, "options": { "shared": ["OFF"] }, "defaultOptions": { "shared": ["OFF"] } } }, { "fromVer": "v1.2", "matrix": { "require": {}, "options": { "shared": ["ON"] }, "defaultOptions": { "shared": ["ON"] } } } ] }Rules:
rangescontains every FormulafromVer, ordered highest to lowest by the module comparator.formulasuses the same order andformulas[i].fromVer == ranges[i].matrixreuses the Formula Matrix shape.matrix.require,matrix.options, andmatrix.defaultOptionsaremap[string][]string.matrix.optionsandmatrix.defaultOptions, matching the currentDefaultsbehavior that initializes the active option selections and their defaults.requireobject when the Formula declares no target requirements.filteris not a separate JSON field. Future capability data uses the Matrix structure.rangesis a boundary list, not synthesized{min,max}objects.Module Mode
The
-mflag switches to Module mode:{ "path": "google/highway", "versions": [ "v0.7.0", "0.11.0", "0.11.1", "1.4.0" ], "deps": {} }Rules:
versionscontains every known upstream tag, preserving original strings and ordered lowest to highest by the module comparator.depsexactly preserves the version-keyedversions.jsonshape.depsmeans static declarations and pins only.depsmust not be interpreted as the effective dependency graph for a concrete version and matrix.Module Selection
With no module argument, the command walks from the working directory to the nearest
versions.jsonand uses that local module.An explicit local path selects that Formula checkout. An explicit module path selects that named module. A
module@versionargument is invalid in both modes.Output And Errors
--jsonwrites one JSON object per selected module to standard output. Diagnostics go to standard error. A failed query exits non-zero and must not emit a partial object.Without
--json, the command may render the same selected mode for humans. Human-readable output is not the automation contract.Missing maps and arrays in the contract are encoded as
{}and[], nevernull.The command returns an error for an invalid module path,
module@version, missing or invalidversions.json, Formula loading failure, comparator failure, or upstream version-query failure.The command must not build, install, test, download artifacts, resolve dynamic dependencies, or mutate artifact-cache state.
Static And Resolved Dependencies
The two
depscontracts remain distinct:For a concrete resolution, LLAR selects the Formula for the requested source version, injects the matrix, runs
filterandonRequire, usesversions.jsonfor pins or fallback, and then runs MVS.llar listperforms none of those steps fordeps.Architecture Boundary
The module loader owns module paths, Formula discovery, custom version comparison, Matrix metadata, and dependency resolution. Formula mode exposes Formula boundaries and Matrix data. Module mode exposes upstream versions and the static
versions.jsontable. The CLI owns mode selection, argument parsing, and rendering. LLARHub owns combining these facts with GitHub metadata and CI results.Implementation must expose only the minimum internal data required by the CLI. It must not expose interpreted Formula callbacks, build contexts, cache internals, or resolver policy as a public API.
Compatibility
This proposal is additive. It changes no existing
make,install,test, Formula DSL,versions.json, cache, artifact, or comparator behavior.Alternatives Considered
Separate defaults, options, and filter fields
Rejected because Formula already owns
Matrix{Require, Options, DefaultOptions}. Reusing Matrix provides one consistent contract.One Formula JSON object per Formula
Rejected because callers need one module-level catalog containing the ordered ranges and corresponding Formula records.
Synthesized
{min,max}rangesRejected because Formula selection is defined by ordered
fromVerboundaries and the last Formula has no finite upper bound.Treat static dependencies as effective dependencies
Rejected because
onRequiremay change dependencies for a concrete source version and matrix.Separate
llar inspectRejected because default Formula mode and explicit
-mModule mode already provide the required boundary.Include artifact availability
Rejected because
make --jsonandinstall --jsonown result data. Read-only artifact inventory requires a separate storage-enumeration design.Acceptance Criteria
llar list <module> --jsonemits one Formula catalog object with onlypath, orderedranges, and same-orderformulascontainingfromVerandmatrix.require,options, anddefaultOptionsmaps shaped asmap[string][]string.matrix.optionsandmatrix.defaultOptions.llar list -m <module> --jsonemits onlypath, comparator-orderedversions, and the unchanged staticdepstable.versions.json.module@versionis rejected in both modes.{}and[], notnull.