phpbotscout index sources¶
Lists every repository discovery found, and the exact clause of the corpus predicate that admitted or rejected it.
Usage¶
$ phpbotscout index sources
SOURCE VERDICT CLAUSE REASON
phpboyscout/go/config indexed none public, in-group, documented
phpboyscout/go/config-toml indexed none public, in-group, listed; no docs site, indexed for readme, code and changelog
phpboyscout/go/cloudevents rejected feed absent from projects.json
phpboyscout/blog rejected visibility visibility is "private", not public
phpboyscout/iac/landing rejected visibility visibility is "private", not public
phpboyscout/infra rejected excluded permanently excluded by "phpboyscout/infra"
<n> of <m> sources qualify; feed generated 2026-10-27T11:45:44Z, fetched 2026-10-27T12:00:03Z.
The last line also says which copy of the estate feed decided the listing: a fresh one, as above, or
stored copy from <time>; fetch failed when the fetch failed and the last good copy was used.
Why rejections are shown¶
Every candidate is listed, rejected ones included, because a source listing has to explain an absence. A repository that simply vanished from the output would send an operator hunting for a bug in discovery when the answer is that the predicate did its job.
A predicate nobody can inspect is a curated list with extra steps.
Clauses¶
| Clause | Meaning |
|---|---|
none |
Nothing rejected it. |
excluded |
On the permanent exclusion list — infra, sandbox, scoutdm, scoutdm-site. Checked first and absolute; no later clause can readmit it, and an excluded repository is never read from at all. |
namespace |
Outside the phpboyscout group. |
visibility |
The forge did not report it as public. Allowlisted against public rather than denylisted against private, since != private would admit both unknown and internal. This is the clause doing the real work — every exclusion-list entry is also private, so the deny list is a second lock rather than the control. |
archived |
The forge reports it as retired. |
feed |
The estate feed, projects.json, does not list it: absent from projects.json or listed false in projects.json. The feed is canon for which sources may be indexed. |
no-docsite |
No zensical.toml marker, and either outside phpboyscout/go/, phpboyscout/rust/ and phpboyscout/images/ or an empty repository with no default branch. |
no-pages |
A zensical.toml marker but no publicly reachable documentation site, wherever the repository is. |
unresolved |
A fact the predicate needs could not be determined — the forge returned an error that was not "not found". Not a rejection on the merits: the source may well qualify, and the next run asks again. |
unresolved exists because "no" and "I could not find out" demand opposite
handling. Reading a repository's zensical.toml can fail with a 404 — which
genuinely means no marker — or with a 500, which means nothing at all. Treating
the second as the first would drop a documented repository out of the corpus
silently, and a different one on the next run. The same applies to the Pages
lookup, where a 403 is routine because reading Pages settings needs the
Maintainer role.
An unresolved check never replaces the verdict a source already has. A source
that qualified keeps qualifying, and keeps its indexed pages, while the failure
is recorded against it for index status to show. The next
decided check clears the failure.
A source the listing no longer contains is retired: renamed, moved out of the
group or deleted, it stops qualifying and its pages stop being cited. It does
not appear in this listing, which shows only what discovery found, but its row
stays in the index with the clause unlisted. Discovery refuses a partial
listing, so a failed enumeration never retires anything, and neither does an
empty one.
When the forge rate limits discovery, discovery stops asking it. Every source it
had not reached is unresolved, with a reason such as not checked: the forge
is rate limiting this caller (it asked for 30s), and the next scheduled refresh
tries again. Sources the listing alone decides, such as a private repository,
are still decided.
archived and feed are evaluated after the screen (exclusion, namespace, visibility) and before
anything else is asked of the forge, so a repository the feed does not list costs no further request.
An archived repository is a judgement about usefulness, not about whether a source is permitted: its
documentation is unmaintained, which for a bot answering questions is worse than absent.
A listed, public project in phpboyscout/go/, phpboyscout/rust/ or phpboyscout/images/ with no
docs site is indexed for its README, code and changelog, never for docs, which would have no page to
cite. Family members, such as the config adapters and the chat providers, are admitted the same way.
The estate feed¶
Discovery reads the feed once per run, from index.feed.url. A feed
that fetched and parsed is stored in the database, and used whenever a later fetch fails, however old
it is; a run using a copy more than 24 hours old logs a warning. The refresh never fails because of
the feed.
With no feed at all, fetched or stored, every source past the screen is unresolved. A source that
already had a verdict keeps it, and a source seen for the first time stays out until a feed is
available.
The feed can only narrow what the forge reports, plus admitting a public, unarchived, non-excluded no-site project in the three groups. It cannot reach a private or excluded repository, because the screen runs first and never consults it, and a path it lists that the forge did not return has no effect.
Where the facts come from¶
Three forge capabilities, all optional in the contract and all required here:
| Capability | Answers |
|---|---|
Repositories |
what is in the namespace, with visibility and archived state |
Contents |
whether the repository carries zensical.toml |
Sites |
where its documentation is published |
The estate feed adds whether the estate lists it, and its family and role.
A provider implementing none of them is conformant, so their absence is refused
at startup rather than tolerated. Without Contents, every repository would be
reported as undocumented — which reads as a fact about the repositories when it
is really a fact about the provider.
Subgroups and archived repositories are both requested explicitly, because the
forge excludes them by default and both defaults fail silently: the entire Go
toolkit lives under phpboyscout/go/*, and a filtered listing looks exactly like
a complete one.
Why a configured list is refused¶
Discovery enumerates from the forge API and will not fall back to a list of sources in your config file.
A configuration file asserting a repository is public would replace the check that keeps an infrastructure repository out of a public channel with the operator's memory. Configuration is a request to index and never an authority on visibility — a checkout cannot say whether a repository is still public, still in the group, or even which project it is, and one made private yesterday looks identical on disk.
Flags¶
sources defines no flags of its own. Global flags (--config, --debug,
--output, --ci, --accessible) are inherited from the root command.
| Name | Description | Default |
|---|---|---|
-h, --help |
Help for sources. |
false |
See also¶
- What the bot is allowed to read — the predicate, clause by clause, and why it is a security boundary
index build— index what qualifies