fleet_list's members rows hand every worker another lead's roster and its owner; CallerResolver#members() has no caller #710
Closed
opened 2026-10-04 06:41:13 +02:00 by ltms
·
3 comments
No Branch/Tag Specified
main
worker/702-4f5c7f-2
worker/715-5c43fc-1
worker/721-70f9ea-5
worker/718-99362b-2
worker/task-15-af0d10-12
worker/task-16-50a702-13
worker/task-12-4d0479-9
worker/task-13-823ce2-10
worker/705-ticket-owner-af9928-8
worker/703-list-collaborators-9c06c2-7
worker/669-example-truth-0b303d-6
worker/669-collab-deliverability-9ba859-3
worker/669-collab-reload-report-2a21bd-4
worker/669-7e80a6-1
worker/669-unit-d-efbbd7-1
worker/669-1b786a-1
worker/669-1d1d9f-1
worker/692-4afb9d-2
worker/689-02fced-13
worker/693-cf23fa-14
worker/677-fix-lead-collision-f69073-12
worker/638-fix-overmask-dbb1bf-11
worker/675-5b7478-4
worker/669-unit-a-70cc8f-3
worker/677-8cdaaf-5
worker/638-a7b391-1
worker/683-4536d6-2
worker/651-a75bbe-8
worker/680-20607d-7
worker/664-c12e95-3
worker/668-08534d-4
worker/672-0f2469-2
worker/670-7d1022-1
worker/661-ac7c28-2
worker/664-37fb9b-3
worker/663-remove-3arg-read-3f6783-1
worker/659-remove-dead-backcompat-ba5e6f-1
worker/637-revision-60a488-23
worker/656-redact-regression-tests-892903-19
worker/637-context-gauge-threshold-466eb5-16
worker/639-redact-line-numbers-de4ac4-17
worker/641-set-reformat-guard-6f96a4-18
worker/642-herdr-guard-scope-5de0e4-15
worker/650-javadoc-scope-95f3b3-14
worker/612-01e9f7-13
worker/612-a-r4-quarantine-outage-7ab0e8-5
worker/612-a-r9-r11-capacity-coverage-peers-cfcc79-7
worker/612-a-r10-loophealth-ccc872-8
worker/612-a-r12-turnregistrar-9e3bb7-9
worker/612-a-r5-leadconfigdir-9e70cf-6
lead/config-edit-redact-anchor-wording
worker/config-edit-seam-ca8dc1-1
worker/612-r67-630-lifecycle-290b8d-3
worker/629-625-ports-seams-da7d5d-4
worker/612-r12-exhaustion-f37cd7-1
worker/612-r38-amqp-24b083-2
worker/fleetd-612-unita-87807e-1
worker/612-b3-mcpwirings-da2b58-3
worker/612-b2-cb185-176d3a-2
worker/612-b1-completion-457459-1
worker/612-agaps-73a926-2
worker/608-sleeps-3a64ff-3
worker/621-b4520b-1
worker/618-b83894-2
worker/fleetd-615-e05481-5
worker/lead-autocompact-5f1ab2-3
worker/fleetd-613-f85deb-3
worker/fleetd-608-flaky-nudge-test-d0c2d1-3
worker/lead-context-gauge-ad404f-1
worker/gauge-wiring-9158c1-4
worker/redeploy-slowstart-ead0e5-5
worker/charter-bytes-13668c-6
worker/rollover-outcome-291483-2
worker/589-f64303-2
worker/593-1a8025-5
worker/589-fcd2aa-1
worker/568-9fdaa2-3
worker/571-attempted-outcome-5739f7-2
worker/581-completionresolver-cas-sites-0542b7-6
worker/562-loop-health-wiring-test-99611c-5
worker/562-surface-loop-health-7df5cc-4
worker/575-waiter-cleanup-sites-62ad80-1
worker/572-answer-lock-release-46a9ae-5
worker/567-probe-channel-leak-a38fc5-6
worker/551-record-before-send-7cbf56-1
worker/561-listener-fanout-survives-a-throw-61d538-2
worker/555-redeploy-main-flow-seam-65c2f5-2
worker/556-injector-owns-registration-e027a5-1
worker/552-post-restart-mktemp-abort-bc2672-4
worker/553-onstatus-completion-leak-0da881-2
worker/550-shasum-linux-196132-1
worker/538-loop-dies-on-error-4a5eeb-6
worker/426-health-coverage-ef1fd4-4
worker/504-failed-reported-clean-3cfd66-3
worker/537-capturedlog-close-e4c437-2
worker/459-broken-link-targets-cadc17-5
worker/535-appender-leak-fe74c1-1
worker/512-part2-shutdown-detection-434701-9
worker/529-logger-level-sweep-2a5533-8
worker/528-drain-gate-call-site-5de83d-7
charter/forge-mcp-vs-token
worker/521-swap-guard-unpinned-28e931-5
worker/519-probe-test-harness-d25ab8-4
worker/525-logger-level-leak-1b4eb0-6
worker/518-fleetmcp-resolver-wiring-8ef96c-1
worker/512-drain-complete-line-7edd71-3
worker/517-abort-branch-and-jar-id-41b641-2
worker/500-9e52c9-3
worker/509-4912f4-2
worker/511-9a4b23-1
worker/493-479f45-2
worker/505-03f8b2-1
worker/492-followup-detect-unclear
worker/501-a31fa0-7
worker/498-451d1c-5
worker/494-1015ce-2
worker/492-209647-1
worker/489-001902-2
worker/480-relative-handover-path-906323-1
worker/480-b-handover-skill-45bf1f-5
worker/474-followup-source-pin-f54a55-17
worker/474-charter-check-on-reload-f54a55-17
worker/466-quarantine-repeatcount-report
worker/393-opencode-skill-seeding-71854b-13
worker/469-canonical-tool-names-2a472a-16
worker/466-quarantine-escalation-5ae9c1-15
worker/446-hot-exhausted-pattern-0af580-6
worker/464-charter-tool-name-guard-a85635-12
worker/463-listfleet-default-fails-open-f1c76c-11
worker/458-invariant-5-by-purpose-862f9a-10
worker/439-coordinator-row-gate-bc032a-8
worker/449-herdr-protocol-576015-4
worker/450-abstract-spawn-599e1c-5
worker/437-ack-refuses-177d91-1
worker/444-placement-window-feb56a-2
worker/440-helddurable-derived-d462d7-13
worker/425-rework-placement-resolve-c58ba1-9
worker/421-lead-peek-held-msgs-cdbad2-10
worker/435-fixed-policy-cap-fe11de-12
worker/422-gate-state-observability-9e79d6-11
worker/431-memberregistry-live-readers-cdbad2-10
worker/424-architect-slot-hot-038b41-7
worker/422-model-gate-spawn-c29f48-6
worker/425-default-profile-live-f55534-8
worker/415-coverage-wording-2cbf9c-5
worker/416-3ad1da-1
worker/418-588283-3
worker/deterministic-stamp-race-409-3cb7b6-10
worker/armed-reads-live-config-404-ed931f-9
worker/reply-peer-refusal-391-5a34bd-7
worker/models-allowlist-aa9e9b-3
worker/ttl-stamp-race-399-f1122f-8
worker/scrub-receipt-400-316b3e-5
worker/exhaustion-detection-395-105105-6
worker/scrub-abort-394-316b3e-5
fix/scrub-uid-abort
worker/task-scrub-517574-2
worker/t386-clock-bd5b78-4
worker/t384-scrub-813790-5
worker/t381-cc-748314-2
worker/t373-336973-2
worker/t365-3920c5-3
worker/t358-6e989b-1
worker/t355-8b321c-1
worker/fleetd-369-hermetic-git-tests-e8b19a-3
worker/fleetd-368-stale-lead-binding-f5682e-2
worker/fleetd-360-deploy-units-0d3793-1
worker/359-dead-lead-tabs-f1253b-4
worker/362-worktree-skills-c03e51-3
worker/361-coord-visibility-655144-1
362-plugin-visibility-and-drift
worker/errscan-bed2ca-2
worker/amqp-log-identity-bed2ca-2
worker/withdefaults-guard-561704
worker/sleepguard-82076d-1
worker/fd334-9ee1b6-5
worker/fd348-f1ab27-4
worker/fd335-a71c35-1
worker/fd342-174a17-2
worker/fd345-490d0f-3
worker/fleetd-337-5ec7d4-21
worker/fleetd-341-af5a6b-24
worker/fleetd-339-5ca0a2-23
worker/fleetd-338-83a4a1-22
worker/fleetd-333-281f46-18
worker/fleetd-329-11bdbb-16
worker/fleetd-330-2770fb-17
worker/fix-326-50506e-15
worker/fix-324-3e9bbf-14
worker/fix-323-b8287d-13
worker/fix-316b-bd0860-11
worker/fix-318-76ca36-9
worker/fix-317-486aec-8
worker/fix-315-ce47c5-6
worker/fix-307-275890-6
worker/fix-308-b4f664-7
worker/fix-309-ec3939-8
worker/fix-310-7a3974-9
worker/fix-302-52ad0e-9
worker/fix-298-ce1acb-8
worker/fix-297-66bd11-7
worker/fix-296-104622-6
worker/fix-293-bare-closetab-eb22b5-3
worker/fix-280-gone-ask-lapse-bca98e-2
worker/fix-290-reapidle-guard-coverage-9b0dd1-1
worker/fix-285-trust-seed-8f3565-10
worker/fix-284-backend-error-seat-85912c-11
worker/fix-282-chained-ask-e6d0bb-8
worker/fix-283-teardown-leaks-f40dfa-9
worker/fix-281-pin-handler-actions-4921ac-7
worker/audit-rendezvous-lifecycle-d072ae-2
worker/audit-health-placement-1a2476-6
worker/audit-teardown-exits-e207a5-3
worker/audit-launcher-asymmetry-27e370-4
worker/audit-rest-authz-6ca53c-5
worker/investigate-275-abandon-asking-fdef52-8
worker/fix-274-worktree-leak-b0095d-7
worker/fix-273-exhausted-pattern-9665b5-6
worker/fleetd-267-model-check-bd8068-1
worker/fleetd-131-archunit-18b834-7
worker/fleetd-266-sshagent-rename-a014ff-6
worker/fleetd-184-uid-claim-8e1f31-4
worker/fleetd-184-warn-b381ee-10
worker/fleetd-184-docs-be1d12-9
worker/fleetd-257-9bf010-7
worker/fleetd-103-23a113-6
worker/fleetd-247-342356-5
worker/fleetd-116-04dea8-4
worker/fleetd-252-a830e0-3
worker/fleetd-111-7e8673-9
worker/fleetd-155c-f8ef4b-8
worker/fleetd-176-b928ca-3
worker/fleetd-249-7a7878-2
worker/cb248-composition-root-b-9acdf7-15
worker/cb148-envrc-default-fa6c82-12
worker/cb201-unit5-wiring-6c12e6-8
worker/cb241-fallback-echo-1175e9-11
worker/cb149-trust-dialog-2392a5-9
worker/cb134-148-overlay-visible-c9b986-10
worker/cb234-session-id-keyed-04e1fc-1
worker/cb201-unit3-nudge-abdf5c-6
worker/cb201-unit2-policy-c1102c-5
worker/cb201-unit4-outcome-a13bfa-7
worker/cb201-unit1-classifier-91b9b1-4
worker/cb201-227-refine-831980-3
worker/cb175-model-readback-0f085f-1
worker/cb222-charter-tmpdir-17f013-1
worker/cb226-architect-slot-race-cd3aa8-3
worker/cb224-worktree-root-group-024523-2
worker/cb-123-role-demotion-c600f7-2
worker/cb-219-opencode-roots-1f677e-1
worker/cb214-claude-session-id-b9eab4-4
worker/cb213-zdotdir-wrong-process-dd6de4-3
worker/cb211-exhaustion-classification-9546e0-2
worker/cb137-ambiguous-task-4df3d8-4
worker/cb209-agentsessionid-4dfdb6-2
worker/cb185-hostenvnames-2692b5-3
worker/cb206-opencode-sqlite-128718-2
worker/cb185-worktree-group-fc0c99-1
worker/cb-137-ask-ticket-e7760c-2
worker/cb-172-broker-uri-d36ae4-4
worker/cb-175-model-readback-76ead6-3
worker/cb-161-pane-ancestry-293510-1
worker/cb-164-rebase-885863-8
worker/cb-164-empty-scrape-false-success-1a80af-3
fix/cb-197-ticket-ttl-from-completion
worker/cb-189-remote-url-coverage-4692f3-1
worker/cb-185-blockers-027756-4
worker/cb-192-gap-log-11b631-2
worker/cb-633-fix-5f4396-3
worker/cb185-router-d6436d-3
worker/cb185-router-routing-gaps-9e9d33-3
worker/cb185-paneids-992586-2
worker/cb-633-allow-list-union-ed374b-1
worker/cb-157-credential-in-remote-url-496e44-2
worker/cb-641-health-herdr-evidence-8f1f54-6
worker/cb-640-health-msg-evidence-99c9cd-1
worker/cb-642-fleets-status-skill-bbbc40-5
cb-634-ide-mcp
worker/lead-comms-wiring-c014b9-7
worker/lead-mailbox-c19577-6
worker/autocompact-window-82bc2f-5
worker/cb-634-probe-18056f-4
worker/cb635-broker-urienv
worker/cb-632-config-retry-8e0efa-7
lead/cb-622e-claude-md
lead/cb-622-followup
worker/cb-622a-165dff-1
lead/cb-622d-opencode-mount
worker/cb-622b-717c67-2
worker/cb-622c-ab7759-3
worker/cb-617b2-20ca4b-3
worker/cb-617a-5c2f4a-1
worker/cb596-4e49ef-3
worker/cb586-10500c-1
worker/cb-606-b9343a-25
worker/cb604-1445f8-24
worker/cb582-477374-21
worker/cb584-8c2281-22
worker/cb600-e6b9a9-20
worker/cb602-ce257f-19
worker/cb601-b42837-18
worker/cb598-6c7ba7-17
worker/cb599-740fe4-16
worker/cb597-282224-15
worker/cb590fix-185e9a-10
worker/cb528-recovery-race
worker/cb594-96bead-8
worker/cb590-916766-2
worker/cb527-997d99-3
worker/cb592-env-leak-3cbf9c-1
worker/cb588-async-ticket-nudge-3218f7-5
worker/cb578b-9dcb13-6
worker/cb581-d24826-5
worker/m2-u5-ef8c42-15
worker/cb578a-516499-2
worker/cb576-01a04b-17
worker/cb579-lead-tab-acba06-20
worker/cb580-terminal-health-ed6058-21
worker/cb577-f36fdc-18
worker/cb573b-3db06f-16
worker/cb568c-f36fdc-18
worker/cb568-drop-cause-c3ac1c
worker/cb575-cancelled-notification-c3ac1c
worker/m4-sol-a2cbec-3
worker/cb574-async-ask-c3ac1c
worker/cb573-health-model-8ca857-14
worker/cb572-unknown-target-7f2e35-13
worker/u4-700706-9
worker/u3-b9fcb6-6
worker/u2-ef5b68-4
worker/u1-469dce-1-clean
worker/u1-469dce-1
worker/cb-564-health-events-70cf7e-2
worker/cb-565-recycle-drops-role-98e58f-3
worker/cb-563-missing-reply-df2866-1
worker/cb-562-readiness-gate-silent-6c23c9-3
worker/cb-560-architect-presence-da8155-1
worker/cb-561-architect-silent-off-a71cab-2
worker/cb-548-bind-architect-slot-fe1b8c-1
worker/parity-overlay-settings-5fb711-1
secrets-central-store
cb-559-hot-key-correction
cb-557-fleet-role-pools
worker/cb-553-maxload-explicit-spawn-305ee3-6
worker/cb-551-idle-lead-heartbeat-f1633c-1
worker/cb-544-drain-preserves-worktree-925fad-3
worker/cb-552-docs-sync-1cb9cf-4
worker/cb-548-rendezvous-guard-rebased
worker/cb-548-rendezvous-guard-116b53-10
worker/cb-548-authz-v2-586df6-8
worker/cb-548-authz-264363-5
salvage/cb-528b-codex-home
salvage/cb-528a-codex-launcher
CB-518-primary-flow
feature/peer-launcher-spi
cb-103-injector
v1.1.0
v1.0.0
Labels
Clear labels
blocked
needs-live-proof
ready-to-delegate
silent-default
Cannot start until something else lands. The body says what.
Merged and green, but never shown working on the running daemon. Not the same as done.
Scope, files and acceptance criteria are written. A worker can be briefed from the body alone.
A feature that compiles, passes tests, and ships turned off. Nine recurrences and counting.
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: fleet/fleetd#710
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two findings from reviewing PR #709 (#703), both reported by the implementer as out-of-scope
observations and both checked by me afterwards.
1.
membersrows expose every member on the daemon, and its owner, to anyREADholderSessionManager.roster()isList.copyOf(registry.values())with no owner filter, andFleetMcp.java:1360-1361addsownerto every row unconditionally:fleet_listis gated onREAD, which a worker holds. So a worker can read every member on thedaemon — including members belonging to a different lead — and which pane owns each one. This
is the same shape #703 narrowed for
collaborators: per-person data whose visibility is decided bythe action alone.
The exposure is small on a single-lead host, because a worker can already read the
leadsrows andtheir session ids, so
ownermostly repeats what it can see. It stops being small as soon as twoleads share a daemon, which is a direction the project is heading: a worker could then map another
lead's whole fleet and who owns it.
Not urgent, and I have not decided the fix. The two candidate shapes are to narrow
ownerby rolethe way
coordinatorandcollaboratorsare narrowed, or to filter themembersarray to thecaller's own owner when the caller is a member. Those differ in behaviour, not just in size, so it
wants a decision rather than a patch.
2.
CallerResolver#members()has no caller outside its own testThe architect-terminal
terminal_id → slot namemap. Its only use outside the resolver isCallerResolverTest.java:463. This is the same "accessor with no caller" shape that #703 found oncollaborators()— and there, the missing caller was the symptom of a missing feature, becauseknownLeadOrCollaborator()read the field directly instead. Worth checking whether the same istrue here, or whether it is simply dead and should go.
Not measured
Nobody has probed either finding from a live worker session. Both are read from the source:
finding 1 from
roster()and the payload builder, finding 2 from agrepfor callers.Finding 1 is wrong. Withdrawing it — the guard exists.
FleetMcpAuthzTest.theFleetListHandlerActuallyConsultsCollaboratorsVisibleTowas added in PR #709and does exactly what I said was missing. It scrapes the
listHandlerblock and asserts both:It carries the same control assertion as its coordinator twin — that the scraped block contains a
listFleet(call at all, so a drifted anchor fails loudly instead of passing on nothing. Itsjavadoc even states the reason in the terms I used against it: "the predicate above can be
perfectly correct while the one production call site never asks it."
So changing the call site to a literal
truewould turn a test red. There is no gap.How I got it wrong
I read the production diff with a
grep, and the test diff only forFleetMcpTest. I saw the newFleetMcpTesttest supply the boolean itself, correctly concluded that that test does not provethe wiring, and then concluded nothing else did either — without ever looking at the
FleetMcpAuthzTesthalf, which was the other 52 lines of the same diff.That is reasoning from an absence I never probed for. My own standing rule is that a zero match is
not a finding until a positive probe fires: here the probe was one
grep -n "listHandler"in thetest file, and I did not run it. I wrote a ticket and a PR comment on the strength of a partial
read.
The thing that caught it was the PR body claiming a source-scrape that the member's own reply had
not itemised. I nearly dismissed that as the description overstating the work. The disagreement
between two accounts of the same change was the signal, and the right response to it is to read the
code, not to pick the account that matches what I already believed.
What this says about the review, not just about me
The member built the guard and then under-reported it: its
fleet_replylisted only the roletruth-table test under the acceptance criterion, while the PR body listed both. The report was
honest, just incomplete in the direction that cost it credit. Worth noting for briefs — asking for
"each criterion with its result" got me a summary per criterion rather than a list of what was
actually added.
The ticket now covers findings 2 and 3 only
Both still stand, and I verified both myself:
SessionManager.roster()isList.copyOf(registry.values())with no owner filter, andFleetMcp.java:1360-1361addsownerto every member row unconditionally, so anyREADholder— including a worker — reads every member on the daemon and which pane owns it.
CallerResolver#members()has no caller outsideCallerResolverTest.I have retitled the ticket accordingly.
fleet_list: the collaborators wiring is unpinned, and members rows still hand every worker another lead's rosterto fleet_list's members rows hand every worker another lead's roster and its owner; CallerResolver#members() has no callerDecision on finding 1, settled by an architect
I was blocked on which shape to use, so I put it to an architect rather than to the operator. The
decision below is theirs; I have checked the load-bearing parts myself and I am acting on it.
Chosen: (d) — omit the whole
memberskey for a worker, and omitleadstoo. Not an emptyarray: the key is absent, so a caller cannot read "not allowed" as "no sessions exist". The primary
and architect views do not change.
Why not the other two
(b) narrow
owneronly — too weak. Withownergone a member row still carriessessionId,paneId, profile, role, state, failure detail, worktree, branch,agentSessionId, charter factsand live status.
(c) filter by owner — wrong meaning of ownership.
ownerTerminalrecords who spawned themember, not who owns the current turn; the current delegator lives in the separate
PrimaryRegistry. And an architect cannot spawn (Authz.java:105,case SPAWN, STOP, DRAIN, HANDOVER -> caller.isPrimary()), so every member it delegates to stillrecords the primary as
ownerTerminal. An owner filter would hide those members from the architectthat is working with them. I verified the
Authzline myself.The rule, which is the part I actually wanted
Facts about the caller come from
fleet_whoami, which already returns a worker's own session,profile, state, worktree, branch and owner. Applying the rule leaves
members,leads,collaboratorsandcoordinatorall absent for a worker; the last two already behave that way.An architect keeps
membersbecause it maySENDto a member; a worker may notSENDat all.Evidence that no worker flow needs
fleet_listThe architect searched for one and found none: no
fleet_listin any.claude/agents/*.md; notnamed in the member turn contract in
CLAUDE.md; in.claude/**/*.mdit appears only infleets-status,handoverandredeploy-fleetd, all marked primary-side. TheRun fleet_listnudge in
ReplyPushLoopgoes to the delegating lead's pane, not to a worker.One correction I am adding to the implementation criteria
The architect said to "reverse the worker expectations" at
FleetMcpTest.java:771-797. I read thattest and it is not a policy pin. Its two lines
are the controls for #439's
assertFalse(out.contains("\"coordinator\"")). They exist so thattest cannot pass because the payload came back empty. Deleting them would make a security
assertion blind.
So: keep a control, move it.
healthCoverageandloopHealthare put unconditionally and stayvisible to a worker, so anchor the control on one of those.
Still not measured
Nobody has called
fleet_listfrom a live worker session, before or after. The whole decisionrests on the source path and unit tests. The architect said so plainly and I am repeating it here.
Also found, not designed
GET /memberson REST has the same coarseREADgate and the same unfiltered roster(
FleetApp.java:79-80,455-478). That is the same REST-door pattern I measured on #705's ticketgate, so it is not a one-off.
Both findings are fixed. Closing.
Finding 1 — PR #717, merged as
f4e0ca4. The chosen fix is wider than either candidate shape inthe ticket text: instead of narrowing
owneror filteringmembersto the caller's own rows, thewhole array is withheld from a worker, and the key is absent rather than present-and-empty. That
subsumes both candidates, because a worker now gets no row at all rather than a trimmed one.
One thing changed during review that the ticket text does not predict. The first implementation
hid
leadsandmembersfrom a collaborator as well as a worker. That breaks a shipped grant: acollaborator may only
fleet_sendto a lead, andleadsis the one place the bridge gives it thataddress. The final split follows the rule
wiki/11-Features.mdalready states for the siblingcollaboratorsarray — you may list what you could address:leadsmembersA worker gets neither, which is what this finding asked for.
Finding 2 — PR #713, merged as
25d53e6. The accessor was dead and is gone.The "not measured" caveat still stands
Neither finding was ever probed from a live worker session, and that is still true. Everything is
pinned by unit tests: truth-table tests on the two predicates, source-scrape tests proving the one
production handler asks them, and a behavioural test asserting no row fragment reaches a worker's
output. I verified the pair holds by mutation — dropping the collaborator clause from
leadsVisibleTocompiled green and then killed exactly two tests, one of each kind.wiki/11-Features.mdis updated. Itsfleet_listentry had three separate errors, one of which thischange created, and it now carries the visibility table plus a gotcha saying what an absent key
means: "you may not see this", not "there are none".