Chart rule contribution guide
This directory contains the declarative statistics shown on LibChecker's chart
page. A rule describes the data that LibChecker should inspect, the condition
that produces a match, and the labels and icon shown to the user.
Rules cannot execute scripts or arbitrary code. LibChecker owns all APK, DEX,
manifest, and native-file traversal. A rule can only use evidence and operators
that the installed app already implements.
Before you start
Answer these questions before writing JSON:
- What does the chart measure, and why is it useful to LibChecker users?
- Which installed-app evidence proves a match?
- Can an app produce one yes/no result, or can it match several capabilities?
- Is there a primary HTTPS source that explains the technology or capability?
- Can you test the rule against both matching and non-matching APKs?
Schema v1 supports only the evidence listed in
Evidence reference.
If your rule needs another source, such as a DEX field, resource-table entry,
native symbol, certificate property, or arbitrary file content, propose a
generic evidence provider in the LibChecker app first. Do not encode a
workaround in the rule.
New rules should normally start with
"releaseChannel": "preview-only"
. Move
them to
only after the preview bundle has been tested with a compatible
LibChecker build.
Contribution workflow
- Fork the repository and create a topic branch.
- Choose the closest example in :
- for exact native-library detection.
- for exact APK entries with a DEX
fallback.
- for facets, recursive conditions, DEX
queries, and manifest receiver actions.
- The predicate example below for a numeric
comparison.
- Add one UTF-8 JSON file under . Use four-space indentation and name
the file after the final segment of the rule ID.
- Add the referenced SVG under .
- Update the tests that enumerate rule IDs, icons, catalog size, and stable
channel contents. Add focused assertions for the new detection data.
- Run the unit tests and build a preview bundle in a temporary directory.
- Test the preview rule with known matching and non-matching apps.
- Regenerate and with the
bundle version and minimum app version agreed for the target branch.
- Submit the source rule, icon, tests, generated bundle, and manifest in one
pull request. Include your evidence source and manual test results in the PR
description.
Run commands from the repository root:
shell
python3 -m unittest chart.tools.test_build_bundle
python3 chart/tools/build_bundle.py \
--bundle-version 12 \
--channel preview \
--minimum-app-version-code 2731 \
--output-dir /tmp/libchecker-chart-preview
The numbers above are examples. Read
chart/cloud/v1/manifest.json
and the
target branch before choosing a bundle version or minimum app version.
Repository layout
| Path | Purpose |
|---|
| Reviewed source definitions, one JSON file per statistic. |
| SVG assets referenced by source rules. |
schema/v1/chart-rule.schema.json
| Machine-readable schema for source rules. |
schema/v1/manifest.schema.json
| Machine-readable schema for the generated manifest. |
| Validator and deterministic bundle generator. |
tools/test_build_bundle.py
| Source validation and bundle regression tests. |
| Generated catalog and icons consumed by LibChecker. |
| Generated version, compatibility, size, and checksum metadata. |
Minimal rule
This is a complete single-predicate rule:
json
{
"id": "official.example-sdk",
"revision": 1,
"source": "official",
"releaseChannel": "preview-only",
"title": {
"translations": {
"en": "Example SDK",
"zh-Hans": "示例 SDK"
}
},
"details": {
"description": {
"translations": {
"en": "Example SDK provides a documented capability for Android apps.",
"zh-Hans": "示例 SDK 为 Android 应用提供一项有公开文档的能力。"
}
},
"referenceUrl": "https://example.com/android-sdk"
},
"icon": {
"asset": "icons/example-sdk.svg",
"renderMode": "monochrome",
"tintRole": "on_surface"
},
"calculation": {
"kind": "predicate",
"predicate": {
"evidence": "native_library",
"operator": "contains",
"value": {
"string": "libexample.so"
},
"matchedTitle": {
"translations": {
"en": "Example SDK apps",
"zh-Hans": "示例 SDK 应用"
}
},
"unmatchedTitle": {
"translations": {
"en": "Other apps",
"zh-Hans": "其他应用"
}
}
}
},
"fingerprint": "artifact"
}
Top-level fields
The source schema does not allow unknown fields. The following fields are
available to official online rules.
| Field | Required | Type or allowed values | Meaning |
|---|
| Yes | String matching | Permanent identity of the statistic. |
| Yes | Integer, minimum | Version of this rule definition. |
| Yes | | Online rules in this repository are official rules. |
| Yes | Translated text | Chart title shown by LibChecker. |
| Yes | Object | In-app description and primary reference URL. |
| Yes | Object | Bundled SVG and its rendering behavior. |
| Yes | or | How apps are classified. |
| No | or | Controls which generated bundle includes the rule. Defaults to . |
| No | | Availability gate. Schema v1 online rules only support . |
requiresFeatureInitialization
| No | Boolean | Hides the chart until feature initialization finishes. Defaults to . |
| No | Empty array only | Online controls are not supported in schema v1. |
| No | | Online dashboard integrations are not supported in schema v1. |
| No | , , or | Selects the app-data fingerprint used to invalidate cached chart results. |
JSON Schema
values document client defaults. The bundle builder does
not insert missing optional fields into the generated catalog.
The ID must match:
text
^official\.[a-z0-9]+(?:[.-][a-z0-9]+)*$
Examples:
- Valid: ,
official.android-api-level
,
official.vendor.capability
.
- Invalid: , , .
Use a specific, technology-neutral ID. Once a rule has been published, never
reuse its ID for a different statistic. The source filename should match the
last ID segment, such as
in
.
Start a new rule at revision
. Increase the revision whenever a published
rule changes its matching logic, titles, description, icon, calculation type,
or other presentation metadata. A change to repository documentation alone
does not require a rule revision.
The revision belongs to one rule. It is independent of the generated bundle's
.
Every rule submitted to this repository must use:
The builder rejects other values.
Translated text
,
, predicate group titles, and facet titles use
the same wrapper. Optional facet short titles use it as well:
json
{
"translations": {
"en": "English text",
"zh-Hans": "简体中文文本"
}
}
Translated-text parameters
| Parameter | Type | Required | Allowed values and limits | Meaning |
|---|
| Object | Yes | 2 to 16 locale entries; must include and | Maps locale tags to the text shown by LibChecker. |
| String | Yes for each declared locale | Non-empty; 80 characters for chart and group titles, 40 for facet titles and short titles, 1,500 for descriptions | Localized value for one BCP 47-style locale tag. |
| Locale key | Allowed | Meaning |
|---|
| Required | English text and runtime fallback. |
| Required | Simplified Chinese text. |
| , | Rejected | These tags are intentionally not accepted; use . |
| Other schema-compatible tags | Optional | Additional translations, for example or , up to 16 locales total. |
Rules for translations:
- and are required. English is the runtime fallback.
- Use for Simplified Chinese. and are rejected.
- A translated object must contain 2 to 16 locales.
- Locale keys use BCP 47-style tags accepted by the schema, such as ,
, , or .
- Each translation must be a non-empty string.
- , , and allow up to 80 characters.
- A facet and allow up to 40 characters.
- allows up to 1,500 characters.
- Keep equivalent meaning across locales. Do not add claims to one language
that are absent from another.
Use short labels for chart and group titles. The matched and unmatched titles
name the two result groups, for example
and
.
Details and reference URL
json
"details": {
"description": {
"translations": {
"en": "A neutral introduction to the technology.",
"zh-Hans": "对该技术的中性介绍。"
}
},
"referenceUrl": "https://project.example/documentation"
}
Details parameters
| Parameter | Type | Required | Allowed values and limits | Meaning |
|---|
| Translated text | Yes | and ; 1 to 1,500 characters per locale | Neutral in-app introduction to the technology or capability. |
| String | Yes | HTTPS URL, valid host, no credentials or whitespace, maximum 512 characters | Primary source opened from the introduction dialog. |
Write a short, neutral description of the technology or capability. Do not say
that the currently selected app matches the rule. LibChecker appends the actual
analysis result at runtime. Faceted rules also list the matched facet titles.
- use HTTPS;
- contain a valid host;
- contain no username, password, or whitespace;
- be no longer than 512 characters;
- point to a primary project, standards body, vendor, or platform document.
Do not use tracking links, URL shorteners, affiliate links, search results, or
an unreviewed third-party summary.
Icons
Every online rule references one repository asset:
json
"icon": {
"asset": "icons/example-sdk.svg",
"renderMode": "monochrome",
"tintRole": "on_surface"
}
Icon fields
| Field | Required | Allowed values | Meaning |
|---|
| Yes | | Repository-relative path included in the bundle. |
| No | , | Whether LibChecker applies a theme tint. Defaults to . |
| No | , , , , | Theme color used for a monochrome icon. Defaults to . |
Use
only when the original brand colors carry meaning. LibChecker
does not apply
to an
icon. Use
for a shape
that should adapt to the active theme.
SVG requirements
An SVG must:
- use a viewBox;
- keep the artwork approximately within a centered area so that
icons have consistent optical size;
- remain below 64 KiB;
- be valid UTF-8;
- contain no scripts, styles, text nodes, linked images, entities, external
references, or content.
The validator rejects
,
,
,
,
,
,
,
,
,
, and
.
Convert text to paths and inline any required fill colors.
Choosing a calculation type
Use
when every app belongs to one of two groups. Use
when
one app can match several named capabilities and the UI should show each match
as a chip.
| Question | Use |
|---|
| Does the app target SDK 35 or newer? | |
| Does the app contain ? | |
| Which ITGSA capabilities does the app implement? | |
Calculation parameters
| Parameter | Type | Required | Possible values | Meaning |
|---|
| String | Yes | , | Selects the calculation object that must accompany it. |
| Object | Required when is | See Predicate calculations | Produces matched and unmatched groups from one condition. |
| Object | Required when is | See Facet calculations | Produces matched and unmatched groups plus per-app capability chips. |
Only the object selected by
is allowed. Online rules cannot use the
client's built-in
calculation type.
Facets are for overlapping capabilities. Do not use them for mutually
exclusive buckets or numeric distributions. Schema v1 has no online
calculation type for those cases.
Predicate calculations
A predicate requires
,
, and exactly one complete
condition. For a single evidence leaf, put
,
, and
directly in
:
| Parameter | Type | Required | Possible values and limits | Meaning |
|---|
| Translated text | Yes | 1 to 80 characters per locale | Label for apps whose condition evaluates to true. |
| Translated text | Yes | 1 to 80 characters per locale | Label for apps whose condition evaluates to false. |
| String | Required for direct-leaf form | , , , , , | Evidence provider used by the leaf. |
| String | Required for direct-leaf form | Depends on | Comparison applied to the evidence. |
| Object | Required for direct-leaf form | Exactly one value variant compatible with | Expected value for the comparison. |
| Condition | Required for recursive form | One leaf, , , or | Recursive condition used instead of the three direct-leaf fields. |
json
"calculation": {
"kind": "predicate",
"predicate": {
"evidence": "target_sdk",
"operator": "greater_than_or_equal",
"value": {
"integer": 35
},
"matchedTitle": {
"translations": {
"en": "Target SDK 35 or newer",
"zh-Hans": "Target SDK 35 及以上"
}
},
"unmatchedTitle": {
"translations": {
"en": "Target SDK 34 or older",
"zh-Hans": "Target SDK 34 及以下"
}
}
}
}
For logical composition, replace the direct leaf fields with one
:
json
"predicate": {
"condition": {
"any": [
{
"evidence": "native_library",
"operator": "contains",
"value": {
"string": "libexample.so"
}
},
{
"evidence": "manifest_receiver_action",
"operator": "contains_any",
"value": {
"strings": [
"com.example.ACTION_READY"
]
}
}
]
},
"matchedTitle": {
"translations": {
"en": "Example apps",
"zh-Hans": "示例应用"
}
},
"unmatchedTitle": {
"translations": {
"en": "Other apps",
"zh-Hans": "其他应用"
}
}
}
Do not provide both the direct fields and
. Partial direct tuples
are also rejected.
Facet calculations
A facet calculation contains 1 to 8 ordered items:
| Parameter | Type | Required | Possible values and limits | Meaning |
|---|
| Translated text | Yes | 1 to 80 characters per locale | Chart label for apps matching at least one facet. |
| Translated text | Yes | 1 to 80 characters per locale | Chart label for apps matching no facets. |
| Array | Yes | 1 to 8 facet objects | Ordered capability definitions. |
| String | Yes | Lowercase rule-local ID matching the documented pattern; unique within the rule | Stable internal identity of a facet. |
| Translated text | Yes | 1 to 40 characters per locale | Full facet label used in detailed result surfaces and chart chips. |
| Translated text | No | 1 to 40 characters per locale | Compact label used in matched-facet summaries; falls back to when omitted. |
| Condition | Yes | One leaf, , , or | Determines whether this facet matches an app. |
json
"calculation": {
"kind": "facets",
"facets": {
"matchedTitle": {
"translations": {
"en": "Example capability apps",
"zh-Hans": "示例能力应用"
}
},
"unmatchedTitle": {
"translations": {
"en": "Other apps",
"zh-Hans": "其他应用"
}
},
"items": [
{
"id": "service-kit",
"title": {
"translations": {
"en": "Service Kit",
"zh-Hans": "服务套件"
}
},
"shortTitle": {
"translations": {
"en": "Kit",
"zh-Hans": "套件"
}
},
"condition": {
"evidence": "native_library",
"operator": "contains",
"value": {
"string": "libexample_service.so"
}
}
}
]
}
}
Each item requires:
- a rule-local matching
^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$
;
- a unique, stable ID within the rule;
- a translated of at most 40 characters per locale;
- an optional translated of at most 40 characters per locale;
- exactly one .
An app enters the matched chart group when at least one facet matches. All
matching facet titles are shown as chips in the order declared by
.
Compact matched-facet summaries use
when present and otherwise
fall back to
.
Do not duplicate facet conditions in a separate root
expression.
Conditions
A condition is either one typed evidence leaf or one logical operator.
Additional properties are rejected.
Condition object parameters
| Parameter | Type | Required | Possible values and limits | Meaning |
|---|
| String | Required for a leaf | , , , , , | Selects the app data to inspect. |
| String | Required for a leaf | , , , , ; compatibility depends on | Selects the comparison. |
| Object | Required for a leaf | Exactly one of , , , , | Supplies the expected value. |
| Array of conditions | Required for an node | 1 to 16 children | True when every child is true. |
| Array of conditions | Required for an node | 1 to 16 children | True when at least one child is true. |
| Condition | Required for a node | One child object | Inverts the child result. |
Exactly one operation is allowed. A leaf must contain all of
,
, and
; a logical node must contain only
,
, or
.
Value object parameters
| Parameter | Type | Used by | Allowed values and limits | Meaning |
|---|
| Integer | | Any JSON integer | Numeric comparison target. |
| String | | 1 to 160 safe filename characters | Exact native-library filename. |
| Array of strings | , | 1 to 16 values, each 1 to 160 safe characters for its evidence type | Exact archive entries or receiver actions; any listed value may match. |
| Array of DEX class queries | | 1 to 16 queries | Class queries; any query may match. |
| Manifest attribute query | | One element, one safe attribute name, and one Boolean | Exact application-manifest Boolean attribute and expected value. |
One value object must contain exactly one of these parameters.
Evidence leaf
json
{
"evidence": "native_library",
"operator": "contains",
"value": {
"string": "libflutter.so"
}
}
All three fields are required and must use a compatible combination from the
evidence table below.
Logical operators
| Operator | Value | Result |
|---|
| Array of 1 to 16 conditions | Matches when every child matches. |
| Array of 1 to 16 conditions | Matches when at least one child matches. |
| One condition object | Inverts the child result. |
Example:
json
{
"all": [
{
"evidence": "target_sdk",
"operator": "greater_than_or_equal",
"value": {
"integer": 35
}
},
{
"not": {
"evidence": "native_library",
"operator": "contains",
"value": {
"string": "liblegacy.so"
}
}
}
]
}
Condition limits
- Maximum nesting depth: 8, with the root condition at depth 1.
- Maximum condition nodes: 64 per predicate calculation. A facet rule shares
the same 64-node budget across all facet conditions.
- Maximum children in one or : 16.
- A condition object must define exactly one operation. It cannot mix a leaf
with , , or .
Prefer the narrowest condition that is supported by reliable evidence. A long
condition is not necessarily a more accurate condition.
Evidence reference
| Evidence | Operator | Value object | Match behavior |
|---|
| , , | | Compares the app's target SDK value. |
| | { "string": "<library-name>" }
| Matches an exact native-library filename. |
| | { "strings": ["<entry-name>", ...] }
| Matches when any exact entry exists in the base or split APKs. |
| | { "dexClasses": [<query>, ...] }
| Matches when any query matches one DEX class. |
| | { "strings": ["<action>", ...] }
| Matches when any listed action is declared by a manifest receiver. |
| | { "manifestAttribute": { "element": "application", "name": "android:<name>", "boolean": <Boolean> } }
| Matches an explicitly declared application-manifest Boolean attribute. |
The integer is compared with the target API recorded for the installed app.
The schema does not impose an API-level range, but the value should represent a
real Android API level.
json
{
"evidence": "target_sdk",
"operator": "less_than_or_equal",
"value": {
"integer": 34
}
}
Use
or omit
for a rule that only depends
on target SDK metadata.
The value is an exact
filename, not a path and not a regular expression.
LibChecker checks extracted libraries and libraries packaged in the APK.
json
{
"evidence": "native_library",
"operator": "contains",
"value": {
"string": "libflutter.so"
}
}
The string must be 1 to 160 characters and may contain ASCII letters, digits,
periods, underscores, plus signs, and hyphens. Use
.
This evidence checks exact ZIP entry names across the base and split APKs. It
does not read file contents and does not support prefixes, globs, or regular
expressions.
json
{
"evidence": "archive_entry",
"operator": "contains_any",
"value": {
"strings": [
"META-INF/example.properties"
]
}
}
The list must contain 1 to 16 entry names. Each name must be 1 to 160
characters, use only ASCII letters, digits, periods, underscores, plus signs,
hyphens, and slashes, and must not end in a slash or contain
or
path
segments. Use
.
This evidence reads actions from manifest-declared broadcast receivers across
the base and split APKs. It matches when at least one supplied action is found.
json
{
"evidence": "manifest_receiver_action",
"operator": "contains_any",
"value": {
"strings": [
"com.example.ACTION_TRIM",
"com.example.ACTION_KILL"
]
}
}
The list must contain 1 to 16 strings. Each action must be 1 to 160 characters
and may contain ASCII letters, digits, underscores, periods, and hyphens. Use
.
This evidence reads an explicitly declared Boolean attribute from the APK's
manifest element. A missing attribute does not match, even when
the Android platform supplies the same value as a runtime default.
json
{
"evidence": "manifest_attribute",
"operator": "equal",
"value": {
"manifestAttribute": {
"element": "application",
"name": "android:enableOnBackInvokedCallback",
"boolean": true
}
}
}
The attribute name must use the
namespace followed by an ASCII
letter and up to 79 ASCII letters, digits, or underscores. Schema v1 supports
only the
element and Boolean values. Resource-backed Boolean
attributes are compared after resource resolution. Use
.
accepts 1 to 16 class queries. The outer
list is OR:
the evidence matches when any query matches any class in the app's base or
split APKs.
json
{
"evidence": "dex_class",
"operator": "contains_any",
"value": {
"dexClasses": [
{
"name": {
"operator": "starts_with",
"value": "Lcom/example/sdk/"
},
"stringConstants": [
"com.example.ACTION_READY"
],
"methodReferences": [
{
"definingClass": "Landroid/content/IntentFilter;",
"name": "addAction",
"parameterTypes": [
"Ljava/lang/String;"
]
}
]
}
]
}
}
Each query may contain
,
,
, or a
combination of them. At least one field is required.
DEX class query parameters
| Parameter | Type | Required | Allowed values and limits | Meaning |
|---|
| Object | No | plus | Restricts the class descriptor. |
| Array of strings | No | 1 to 16 strings, each 1 to 160 characters without control characters | Matches if the class references any listed string. |
| Array of method-reference objects | No | 1 to 16 references | Matches if the class references any listed method. |
At least one query parameter is required. If several parameters are present,
all parameter categories must match the same class.
The fields inside one query are AND categories and must be satisfied by the
same DEX class:
- , when present, must match that class.
- , when present, succeeds if the class references any string
in the list.
- , when present, succeeds if the class references any method
in the list.
For example, a query containing both
and
requires one class that contains at least one listed string and at least one
listed method reference. The matching instructions do not have to appear in
the same method. Use separate entries in
when the evidence may be
found in different classes.
Class names
DEX class names use descriptors, not Java or Kotlin dotted names.
| Goal | Operator | Example |
|---|
| Match one class | | Lcom/example/sdk/EntryPoint;
|
| Match a package or nested prefix | | |
| Name parameter | Type | Required | Possible values and limits | Meaning |
|---|
| String | Yes | , | Exact descriptor match or descriptor-prefix match. |
| String | Yes | DEX class descriptor pattern beginning with ; must end in | Descriptor or prefix to match. |
requires the trailing semicolon.
may omit it and usually
uses a trailing slash for a package prefix. Values begin with
and may use
letters, digits, underscores, dollar signs, slashes, and hyphens.
String constants
contains 1 to 16 strings, each 1 to 160 characters. Control
characters are rejected. These strings are literal DEX string references, not
regular expressions or substrings.
Method references
A method reference requires
and
:
json
{
"definingClass": "Landroid/content/IntentFilter;",
"name": "<init>",
"parameterTypes": [
"Ljava/lang/String;"
]
}
| Field | Required | Constraint |
|---|
| Yes | Full DEX class descriptor ending in , up to the schema limit. |
| Yes | DEX method name, 1 to 80 characters. and are accepted. |
| No | Exact parameter descriptor list, at most 16 entries. |
Omit
to match any overload with the same defining class and
method name. Provide it to require an exact parameter list. An empty array
matches a zero-parameter method.
Primitive descriptors are
(boolean),
(byte),
(short),
(char),
(int),
(long),
(float), and
(double). Prefix a descriptor with
for each array dimension. Object types use full descriptors such as
.
Optional metadata
- is the default and is included in both preview and stable bundles.
- is included only when the builder uses .
The builder removes
from the generated catalog. It is a
repository publication control, not runtime chart metadata.
Schema v1 online rules only accept
, which is also the default. Omit
this field unless a future schema adds a supported online availability gate.
requiresFeatureInitialization
When
, LibChecker hides the chart until its feature initialization has
finished. Current online evidence types do not require feature data, so new
online rules should normally omit this field or use
.
Schema v1 allows no online chart controls. Omit this field. An explicit empty
array is valid but adds no behavior.
Schema v1 online rules only accept
, which is the default. Omit it.
The fingerprint controls when LibChecker discards cached chart results after
installed-app data changes. It does not grant access to additional evidence.
| Value | Use |
|---|
| Metadata-based rules such as . This is the default. |
| Rules that inspect native libraries, archive entries, DEX, or manifest contents. |
| Rules that depend on LibChecker's initialized feature data. No schema v1 online evidence currently needs it. |
Choose the fingerprint that covers every evidence leaf in the rule. A rule
that combines target SDK with DEX evidence should use
.
Validation and tests
Run:
shell
python3 -m unittest chart.tools.test_build_bundle
The JSON Schema defines the complete object shape and field constraints. The
Python builder performs additional semantic validation. It rejects incompatible
evidence/operator/value combinations, unsafe URLs, unsafe icon paths and SVG
content, duplicate IDs, duplicate facet IDs, and complexity-limit violations.
When adding a rule, update the existing assertions in
chart/tools/test_build_bundle.py
:
- Add the ID in sorted order to
test_source_rules_are_valid
.
- Add a new icon path in sorted archive order and update the expected catalog
count in
test_bundle_is_deterministic_and_contains_only_expected_files
.
- Update
test_stable_bundle_excludes_preview_only_rules
according to the
rule's release channel.
- Add one focused test that asserts the important detection values, condition
ordering, icon render mode, details URL, or another property that reviewers
should not accidentally change.
- Add negative validation tests when you introduce a new schema capability or
validator branch.
Do not weaken limits or delete regression assertions only to make a new rule
pass.
Bundle generation
For a local preview, write to a temporary directory so that validation does not
modify tracked generated files:
shell
python3 chart/tools/build_bundle.py \
--bundle-version 12 \
--channel preview \
--minimum-app-version-code 2731 \
--output-dir /tmp/libchecker-chart-preview
For the final branch artifact, omit
to write to
:
shell
python3 chart/tools/build_bundle.py \
--bundle-version 12 \
--channel preview \
--minimum-app-version-code 2731
Builder arguments:
| Argument | Required | Meaning |
|---|
| Yes | Positive, monotonically increasing publication version for the target branch. |
| No | by default, or . Preview includes both release channels; stable excludes . |
--minimum-app-version-code
| No | First LibChecker version code that can safely load every rule in the bundle. Defaults to , which should only be published when all supported clients are compatible. |
| No | Destination directory. Defaults to . |
If the rule uses only evidence and calculation features already supported by
the published app, retain the branch's compatible minimum app version. If it
depends on a new client capability, coordinate the app change first and set the
exact first compatible version code. Do not guess this number.
The builder:
- validates every source rule and referenced SVG;
- sorts rules by ID and icons by path;
- writes a deterministic ZIP containing and referenced icons;
- limits the bundle to 64 rules and 2 MiB;
- computes and ;
- writes with schema, publication, and compatibility metadata.
Commit
and
together. A checksum or size from one
generation cannot be paired with a bundle from another generation.
Manual verification
Automated validation proves that a rule is well-formed. It does not prove that
the evidence identifies the intended apps.
Before requesting stable publication:
- Install a compatible LibChecker build that reads the preview branch.
- Check at least one known matching app and one known non-matching app.
- For facets, verify every facet independently and confirm that an app matching
several facets shows all expected chips in rule order.
- Check the chart title, group titles, description, reference link, icon size,
colors, light theme, and dark theme.
- Record the app versions or sample APKs used for testing in the PR description.
- Rebuild with and inspect the catalog before publishing.
Every rule must be absent.
Pull request checklist
Recovery after a bad publication
Do not reuse an older bundle version. Restore the last known-good source rules
and generated contents, then publish them with a higher
.
Compatible LibChecker clients retain their cached bundle when a download,
checksum, schema, or minimum-version check fails.