v0.5.0
Major READ capability expansion — no WRITE change, no security-model
change. Public MCP contract grows from 42 to 84 READ tools (exactly a
100% increase over the last published baseline, v0.4.2), covering
roughly 80% of the useful READ capability universe identified by this
project's own capability discovery audit (267 OpenAPI paths / 243 GET
operations reviewed; every GET given exactly one disposition — up from
roughly 40% coverage at the v0.4.2 baseline). Every tool below was
independently re-verified for secret-bearing fields before
implementation, then verified against a real pfSense instance (LAB or,
where explicitly owner-authorized, production) before public
registration — never assumed from schema alone. Closes with an
independent, adversarial release-readiness audit (security regression
sweep, CE/Plus compatibility verification including a live production
Plus 26.07 pass, packaging/fresh-install/upgrade-path verification, and
a full README restructure) — see "Security" and "Changed" below for its
findings.
Added
- 2 new READ tools (production live-verified, pre-dating the P0
backlog below), public MCP contract 42 → 44 (0 WRITE, unchanged):pfsense_get_firewall_nat_outbound_mappings— outbound NAT
mappings (source/destination/targetaddress/alias fields
redacted by default, matchingFirewallNatPortForward's
established convention;source_hash_keyis a hash seed, not a
credential, and stays visible).pfsense_get_firewall_nat_one_to_one_mappings— 1:1 NAT mappings
(external/source/destinationredacted the same way).- Owner-authorized, narrowly-scoped live production READ
verification (not LAB) of exactly these two endpoints: both typed
GETs succeeded with zero configured mappings in either category;
field-level type/nullability compatibility confirmed via an exact,
byte-for-byte match between the live OpenAPI schema and the pinned
v2.10 reference the models were derived from.
- 7 new READ tools, public MCP contract 44 → 51 (0 WRITE, unchanged):
pfsense_get_interface_vlans— 802.1Q VLAN interfaces.pfsense_get_routing_static_routes— static routes (network/gateway
redacted by default).pfsense_get_interface_groups— interface group membership, useful
for interpreting firewall rules that target a group.pfsense_get_firewall_schedules— time-based firewall schedules.pfsense_get_system_restapi_version— installed REST API package
version and update availability.pfsense_get_firewall_virtual_ips— CARP/IP-alias/proxy-ARP virtual
IPs (address fields redacted by default; the CARP shared secret is
never modeled at all — see "Security" below).pfsense_get_system_certificate_authorities— trusted CA inventory
(the CA private key is never modeled at all — see "Security" below).- Two of the seven (
system_restapi_version,
system_certificate_authorities) were verified against real,
populated LAB objects, not just an empty envelope — the latter
against the LAB's own internal CA.
- 2 more READ tools (P1 Batch A, partial), public MCP contract 51 →
53 (0 WRITE, unchanged):pfsense_get_status_ipsec_sas— live IPsec SA/tunnel status,
including nested child SAs.pfsense_get_status_ipsec_child_sas— live IPsec child SA status.IPsecSaStatus.child_sasembeds fullIPsecChildSaStatusobjects
(schema-confirmed$ref) and is constructed through that model's
own parser for every nested item, not passed through as a raw dict.status/wireguard/tunnels/status/wireguard/peerswere also
implemented and offline-tested this batch but remained unregistered
at first: this LAB did not havepfSense-pkg-WireGuardinstalled,
so live verification was blocked — see the next entry for how this
was resolved.
- 2 more READ tools (P1 Batch A completion), public MCP contract 53 →
55 (0 WRITE, unchanged): owner explicitly authorized installing
pfSense-pkg-WireGuardon the LAB for non-production READ
verification only. Preflight: reconfirmed LAB identity distinct from
production, identified the LAB as the sole pfSense-named VM in its
Proxmox cluster, and took a fresh rollback snapshot before any
change. Post-install: confirmed pfSense/pfREST healthy, re-ran a
52-tool regression subset with zero regressions, then live-verified
both endpoints (HTTP 200, correct envelope, zero configured tunnels/
peers; raw responses inspected directly for unexpected fields).pfsense_get_status_wireguard_tunnels— live WireGuard tunnel
status, including nested peer status.pfsense_get_status_wireguard_peers— live WireGuard peer status.- The package installation was a one-off authenticated LAB
administrative call, made outside and independent of this
project's ownWriteApiClient/WriteEndpointsallow-list
mechanism, which remains untouched and still empty except
FIREWALL_ALIAS_DESCRIPTION— not a WRITE-capability expansion of
the shipped server.
- 4 more READ tools (P1 Batch B), public MCP contract 55 → 59 (0
WRITE, unchanged):pfsense_get_status_openvpn_servers— live OpenVPN server status,
including nested connection/route status.pfsense_get_status_openvpn_clients— live OpenVPN client status.pfsense_get_status_openvpn_server_connections— flat, all-servers
OpenVPN client connection status.pfsense_get_status_openvpn_server_routes— flat, all-servers
OpenVPN client route status.- Resolved the standing open question of whether the standalone
connection/route endpoints duplicateOpenVpnServerStatus's own
nestedconns/routesfields using the pinned schema's own
Parent modeldeclaration (both standalone endpoints declare
Parent model: OpenVPNServerStatus) — the identical structural
relationship already established as non-redundant between
IPsecSaStatus/IPsecChildSaStatus, so all four were implemented
as genuinely independent capabilities rather than assumed
duplicates. OpenVpnServerStatus.conns/.routesembed full
OpenVpnServerConnectionStatus/OpenVpnServerRouteStatusobjects
(schema-confirmed$ref) and are constructed through those
models' own parsers for every nested item, not passed through as
raw dicts.
- 3 more READ tools (P1 Batch C), public MCP contract 59 → 62 (0
WRITE, unchanged):pfsense_get_dns_forwarder_host_overrides— dnsmasq (DNS Forwarder)
host overrides: addresses, aliases, and descriptions.pfsense_get_dns_resolver_domain_overrides— Unbound (DNS Resolver)
domain overrides: forwarding target address and DNS-over-TLS
settings.pfsense_get_dns_resolver_access_lists— Unbound (DNS Resolver)
access lists: allow/deny action and the network ranges each list
applies to.- All three re-checked against the pinned schema for secrets (none
found) and modeled following the existing shipped
DnsResolverHostOverrideprecedent: full field visibility, no
include_identifying_metadataredaction, since address/network
data is the core content of this capability class (the same
rationale already documented forDhcpServer). - All three LAB-verified live:
HTTP 200, zero configured objects
(ENDPOINT_VERIFIED); no package required (base
pfSense/dnsmasq/Unbound features).
- 3 more READ tools (P1 Batch D, interface extras), public MCP
contract 62 → 65 (0 WRITE, unchanged):pfsense_get_interface_available_interfaces— all interfaces
available for assignment (not just already-assigned ones):
identifier, in-use status, hardware boot message.pfsense_get_interface_gres— GRE tunnel interfaces.pfsense_get_interface_laggs— LAGG (link aggregation) interfaces.- All three re-checked against the pinned schema for secrets (none
found).mac(AvailableInterface) and 7 ofInterfaceGRE's 11
fields (tunnel-endpoint addresses) are redacted by default,
matchingInterfaceStatus.macaddrandRoutingStaticRoute's
established conventions;InterfaceLAGG'smembers/laggifstay
visible, matchingInterfaceBridge's established no-redaction
precedent.InterfaceLAGG's proto-conditional fields
(lacptimeout/lagghash/failovermaster) use.get()with the
schema's own declared default, matching theinstall_version
precedent for a field that can be legitimately absent rather than
merely null. interface/available_interfacesLAB-verified with
FIELD_MODEL_LIVE_VERIFIED: 2 real populated objects (the LAB's
actualvtnet0/vtnet1WAN/LAN interfaces), with redaction
confirmed against real data.interface/gresand
interface/laggsboth LAB-verifiedENDPOINT_VERIFIED(zero
configured objects); no package required for any of the three
(base pfSense features).- The models/client methods/
Endpointsentries were implemented and
offline-tested one commit before registration, deliberately
unregistered in the interim, matching the established
"implemented, offline-tested, blocked" precedent from P1 Batch A's
WireGuard pair.
- 5 more READ tools (P1 Batch E, routing + DHCP extras), public MCP
contract 65 → 70 (0 WRITE, unchanged):pfsense_get_routing_gateway_groups— gateway groups: name,
failover trigger, description, prioritized member gateways.pfsense_get_routing_gateway_default— current default IPv4/IPv6
gateway assignment.pfsense_get_dhcp_relay— DHCP Relay configuration.pfsense_get_dhcp_server_address_pools— additional DHCP scopes
across all configured DHCP servers.pfsense_get_dhcp_server_custom_options— DHCP custom options
across all configured DHCP servers.RoutingGatewayGroupPriority.gateway/.virtual_ipand
DefaultGateway.defaultgw4/.defaultgw6(gateway name references)
andDHCPRelay.server(literal relay target addresses) are
redacted by default, matchingRoutingStaticRoute.gatewayand
GatewayConfig.gateway's established conventions.
RoutingGatewayGroup.prioritiesembeds full
RoutingGatewayGroupPriorityobjects and is constructed through
that model's ownfrom_api()for every item.
DHCPServerAddressPool/DHCPServerCustomOptionare schema-declared
children ofDHCPServer(Parent model: DHCPServer) and follow
that resource's own established no-redaction convention instead
("the whole point of a DHCP server (scope) configuration
capability").- LAB verification found a genuine CE 2.9.0 nullability discrepancy:
DHCPRelay.interfacereturnednullon the LAB's unconfigured
DHCP Relay despite the pinned schema declaring itnullable: false
— fixed by widening the field before promoting, matching the
SystemRestApiVersion.install_version/DhcpServerprecedent. - All five reached
ENDPOINT_VERIFIED; no package required for any
of the five (base pfSense features). - The models/client methods/
Endpointsentries were implemented and
offline-tested one commit before registration, deliberately
unregistered in the interim, matching the established
"implemented, offline-tested, blocked" precedent from P1 Batch A's
WireGuard pair.
- 5 more READ tools (P1 Batch F, system identity/config cluster),
public MCP contract 70 → 75 (0 WRITE, unchanged):pfsense_get_system_hostname— system hostname and domain.pfsense_get_system_timezone— system timezone.pfsense_get_system_dns— system DNS settings: override policy,
local-vs-remote resolution preference, remote DNS servers.pfsense_get_system_console— whether a password is required to
access the system console.pfsense_get_system_webgui_settings— web GUI listener settings:
protocol, port, assigned TLS certificate reference.SystemHostname.hostname/.domainare redacted by default (a
conservative-posture judgment call, not a schema-confirmed
secret — they identify the specific managed appliance/network) and
SystemDNS.dnsserver(literal DNS server addresses) is redacted by
default, matchingRoutingStaticRoute.gateway/GatewayConfig.gateway's
established conventions.WebGUISettingswas independently
re-verified secret-free during this batch's own re-check
(protocol/port/sslcertrefonly —sslcertrefis a certificate
reference, not key material).- LAB-verified:
system/hostname,system/timezone,
system/console, andsystem/webgui/settingsall reached
FIELD_MODEL_LIVE_VERIFIED(real populated data, not just an empty
envelope);system/dnsreachedENDPOINT_VERIFIED(no remote DNS
servers configured on this LAB). No package required for any of
the five (base pfSense features). - The models/client methods/
Endpointsentries were implemented and
offline-tested one commit before registration, deliberately
unregistered in the interim, matching the established
"implemented, offline-tested, blocked" precedent from P1 Batch A's
WireGuard pair.
- 3 more READ tools (P1 Batch G, REST API + PKI metadata), public
MCP contract 75 → 78 (0 WRITE, unchanged):pfsense_get_system_restapi_access_list— the REST API's own IP
allow/deny access list entries.pfsense_get_system_crls— Certificate Revocation Lists (CRLs).pfsense_get_system_package_available— packages available for
installation.RESTAPIAccessListEntry.network(the REST API's own literal IP
allow/deny CIDR) is redacted by default, matching
GatewayConfig.gateway's established convention.
CertificateRevocationList.cert/.textare each schema-documented
as only available for a specificmethodvalue and are treated as
genuinely possibly-absent, matching theInterfaceLAGGprecedent.- Found during re-verification that
CertificateRevocationListRevokedCertificatehas five schema
fields markedwriteOnly: true—crt,caref,descr,type,
andprv, confirmed to be the revoked certificate's X509
private key — none of these are ever present in a real GET
response, and none are modeled, matching the
CertificateAuthority.prv/SystemCertificate.prvprecedent
exactly rather than trusting the schema'swriteOnlypromise
alone. - LAB-verified:
system/restapi/access_listand
system/package/availableboth reachedFIELD_MODEL_LIVE_VERIFIED
(2 real default allow-all entries; 69 real available packages);
system/crlsreachedENDPOINT_VERIFIED(zero configured CRLs on
this LAB). No package required for any of the three (base pfSense
features). - The models/client methods/
Endpointsentries were implemented and
offline-tested one commit before registration, deliberately
unregistered in the interim, matching the established
"implemented, offline-tested, blocked" precedent from P1 Batch A's
WireGuard pair.
- 1 more READ tool (P1 Batch H), public MCP contract 78 → 79 (0
WRITE, unchanged):pfsense_get_firewall_traffic_shapers— traffic shapers:
interface, scheduler algorithm, bandwidth, and child queues.- No field is redacted (pure QoS/bandwidth-shaping configuration
data, no addresses). OfTrafficShaperQueue's 27 fields, only 6
are schema-required; the other 21 are each documented as only
available for a specificschedulertype or sibling boolean flag
and are treated as genuinely possibly-absent via.get(),
matching theInterfaceLAGGprecedent. - LAB-verified
ENDPOINT_VERIFIED(zero configured traffic shapers
on this LAB); no package required (base pfSense feature).
- 3 more READ candidates implemented and offline-tested (P1 Batch H,
service/traffic policy cluster) but requiring an absent package —
package-conditional, NOT a LAB-installation authorization:
services/freeradius/interfacesandservices/freeradius/macs
(requirepfSense-pkg-freeradius3) andservices/service_watchdogs
(requirespfSense-pkg-Service_Watchdog). Direct LAB inspection via
the already-shippedpfsense_get_system_packagestool confirmed
neither package is installed on this LAB — only
pfSense-pkg-WireGuardis.FreeRADIUSInterface/FreeRADIUSMAC/
ServiceWatchdogmodels, their client methods, and theirEndpoints
entries (verified=False) all exist and are fully offline-tested,
but are left unregistered pending an owner decision on installing
either package — matching this project's standing
package-conditional-candidate rule (onlypfSense-pkg-WireGuard
installation was ever explicitly authorized).FreeRADIUSInterface.addr
(listening address) andFreeRADIUSMAC.mac/5framed_*address
fields are redacted by default once registered, matching
GatewayConfig.gateway/InterfaceStatus.macaddr's established
conventions. - 3 more READ tools (P1 Batch I, IPsec Phase 2 + encryption
capability lists), public MCP contract 79 → 82 (0 WRITE,
unchanged):pfsense_get_vpn_ipsec_phase2s— IPsec Phase 2 entries: mode,
protocol, encryption/hash options, and rekey timing.pfsense_get_vpn_ipsec_phase1_encryptions— IPsec Phase 1
encryption algorithm/hash/DH-group capability options.pfsense_get_vpn_ipsec_phase2_encryptions— IPsec Phase 2
encryption algorithm capability options.- Re-confirmed the IPsec PSK lives only on
IPsecPhase1, already
REJECTed separately — no secret material is present on Phase 2
itself.IPsecPhase2.localid_address/.natlocalid_address/
.remoteid_address/.pinghost(endpoint and monitoring target
addresses) are redacted by default, matching
RoutingStaticRoute.gateway's established convention.
encryption_algorithm_optionis schema-documented as only
available whenprotocolis'esp'and is treated as genuinely
possibly-absent via.get(), matching theInterfaceLAGG
precedent; it is schema-confirmed to embed full
IPsecPhase2Encryptionobjects and is constructed through that
model's ownfrom_api()for every item.
IPsecPhase1Encryption/IPsecPhase2Encryptionare pure
algorithm/cipher capability reference data, no redaction needed. - LAB-verified
ENDPOINT_VERIFIEDfor all three (zero configured
Phase 2 entries; the encryption capability lists were also empty
on this LAB, since no IPsec Phase 1 is configured to derive
options from). No package required for any of the three (base
pfSense feature).
- 2 more READ tools (P1 Batch J, OpenVPN server config +
client-specific overrides), public MCP contract 82 → 84 (0 WRITE,
unchanged):pfsense_get_vpn_openvpn_servers— OpenVPN server configurations:
mode, protocol, TLS/cert references, ciphers, and topology
(OpenVpnServer, 73 fields).pfsense_get_vpn_openvpn_csos— OpenVPN client-specific overrides:
per-client tunnel settings, allowed servers, and DNS/NTP/WINS
pushes (OpenVpnClientSpecificOverride, 27 fields).- Neither schema component has any
writeOnlyfield, unlike the
Batch G CRL case.caref/certrefare CA/certificate
references, not certificate material, matching this project's
established treatment of reference IDs as non-secret.
tlsauth_keydiris re-confirmed (a fourth time across sessions)
to be a direction-flag enum, not key material. The singular
vpn/openvpn/serverendpoint is redundant with the plural
vpn/openvpn/servers(same underlying model) and is deliberately
not implemented, matching the established NAT-mappings precedent. - Network/address fields (
local_network/local_networkv6/
remote_network/remote_networkv6/tunnel_network/
tunnel_networkv6/dns_server1-4/ntp_server1-2/
wins_server1-2/serverbridge_dhcp_start/serverbridge_dhcp_end
on the server model;common_nameplus the same address-field set
on the client-specific-override model) are redacted by default,
matchingRoutingStaticRoute.gateway's established convention. - 37 of
OpenVpnServer's 73 fields and 5 of
OpenVpnClientSpecificOverride's 27 fields are schema-documented
as only available under a specificmode/use_tls/gwredir/
ping_actioncondition and are treated as genuinely
possibly-absent via.get(), matching theInterfaceLAGG/
TrafficShaperQueueprecedent. - LAB-verified
ENDPOINT_VERIFIEDfor both (zero configured OpenVPN
servers and zero client-specific overrides on this LAB). No
package required for either (base pfSense feature).
Security
- Two confirmed secret-bearing schema fields are never modeled at
all, not merely redacted behind a flag:VirtualIP.password(the
CARP shared advertisement secret between HA peers) and
CertificateAuthority.prv(the CA private key) — mirroring the
already-shippedSystemCertificatemodel's own established treatment
of the identicalprvdistinction. Proven by construction
(hasattr(model, "password"/"prv")isFalse), independently
confirmed against real LAB data for the CA case. - A draft test fixture containing a placeholder
passwordkey was
caught and rejected by this project's ownfixture_safety.py
prohibited-credential-field scan before it reachedmain— fixed by
injecting secret-field values into the raw response only in-memory,
at test time, never in a committed fixture file. SystemRestApiVersion.install_versionis modeled as optional: LAB
verification found it genuinely absent from a real live response (not
merelynull), a compatibility finding the schema alone did not
surface.WireGuardPeerStatus.preshared_keyis confirmed present in the
live status object (not merely the config object) and is never
modeled at all, matching theVirtualIP.password/
CertificateAuthority.prvprecedent exactly.WireGuardTunnelStatus.peers
is schema-confirmed to embed fullWireGuardPeerStatusobjects and is
constructed through that model's own parser for every nested item —
a raw-dict passthrough there would have silently leaked
preshared_keyverbatim into the tunnel-status tool's output.
Independently re-confirmed via the owner's pfREST 2.10 settings-UI
sensitive-field classification, which agrees with every exclusion
this project has already made
(OpenVPNClient.proxy_passwd/.auth_pass,VirtualIP.password,
CertificateAuthority.prv,WireGuardPeer.presharedkey,
WireGuardPeerStatus.preshared_key,WireGuardTunnel.privatekey) —
this project's own model-level exclusions remain the enforcement
mechanism regardless; pfREST's own redaction behavior, if any, is
never relied upon.OpenVpnServerConnectionStatus.common_name/.user_nameand the
analogouscommon_namefields elsewhere in the OpenVPN status
cluster are real per-connection human/device identity data, not
merely network topology — redacted by default like other identifying
fields, with the extra care this class of field warrants noted
explicitly rather than treated as an ordinary address field.- Release-readiness audit (2026-08-21): hardened the global
credential-disclosure regression test.
tests/test_credential_non_disclosure.py'sPROHIBITED_FIELDSset,
which is scanned against every registered tool's full input/output
MCP schema, previously only checked for{ipsecpsk, password, key}
by exact field name — a future field literally namedauth_pass,
proxy_passwd,privatekey,presharedkey,preshared_key, or
prvwould not have been caught by this specific automated check
even though this project has explicitly committed to excluding
every one of those names. Expanded the set to all seven. Confirmed
zero regressions and zero live hits with the expanded set across all
84 registered tools.
Changed
- Release-readiness audit (2026-08-21): independently re-verified and
documented pfSense CE/Plus compatibility. pfSense CE 2.9.0 remains
the LAB VERIFIED baseline (unchanged). Added pfSense Plus
26.07 — LIVE VERIFIED: an owner-authorized, strictly READ-only
production compatibility pass (identity verified first; no
POST/PUT/PATCH/DELETE, no package/config/privilege changes performed)
found the live OpenAPI schema structurally identical to the pinned
v2.10 reference (267/267 paths, 186/186 components — the only
differences across every field were 5 instance-specific runtime
default values, never a type or nullability change), and successfully
exercised 82 of the 84 public READ tools against real production data
(30 of those as valid, meaningful empty envelopes); the remaining 2
(pfsense_get_status_wireguard_tunnels/_peers) were correctly and
automatically classified package-absent (WireGuard not installed on
that appliance, and not installed by this audit) rather than treated
as a failure. Zero genuine incompatibilities found; a targeted
secret-safety re-check against the seven highest-risk live tool
responses found zero prohibited field names. Added pfSense Plus
25.11 — SUPPORTED/COMPATIBLE (not live-verified), an explicit
inference from converging platform/schema evidence (same FreeBSD
16-CURRENT base OS as the verified CE 2.9.0/Plus 26.07 evidence; one
platform-version step from a build already proven to have zero schema
drift; the same pinned pfREST v2.10 package already confirmed
compatible across three separate platform/edition combinations),
explicitly not a test result. - Corrected the published-baseline framing used throughout this
[Unreleased]narrative. Git archaeology (checking
KNOWN_READ_TOOL_NAMES's length at the actualv0.4.2git tag,
cross-checked against README's and v0.4.2's ownCHANGELOGentry,
both of which already correctly said 42) proved the true
last-published baseline this entire READ-expansion audit measures
against was 42 tools, not 44 as this section originally stated.
The correct headline for this release is 42 → 84 public READ
tools, exactly a 100% increase (not 44 → 84 / ~91%). The two
"extra" tools accounting for the discrepancy
(pfsense_get_firewall_nat_outbound_mappings/
pfsense_get_firewall_nat_one_to_one_mappings) were live-verified
against production and registered before this audit's own tracked
narrative began, but had never received their ownAddedbullet —
fixed above. - Full README restructure (key facts → what you can do → why this
server → quick start → requirements/compatibility → MCP client setup
→ capability overview → security model → troubleshooting →
documentation → release status → contributing/license), including a
category-level capability overview table and a symptom/cause/action
troubleshooting table. Structural/UX patterns only (badges,
table-based summaries, per-client setup subsections) were drawn from
surveying other pfSense MCP projects' README conventions for
inspiration — no wording, architecture, or security claims copied
from any external project.
Fixed
- LAB CE 2.8.1 → 2.9.0 platform-upgrade regression (2026-08-21): a
full regression smoke test of all 51 public READ tools against the
freshly upgraded LAB appliance (pfSense CE 2.9.0-RELEASE, FreeBSD
16.0-CURRENT, reinstalledpfSense-pkg-RESTAPIv2.10 — same REST API
version, same 267-path schema, distinct install) found 2 of 51 tools
now fail shape validation:pfsense_get_dhcp_serversand
pfsense_get_dns_resolver_settings. Root cause: for an unconfigured
optional field (e.g. no DHCP scope domain/gateway set, no DNS-over-TLS
certificate configured), the platform now returnsnullwhere the
original 2.8.1 LAB capture had returned an empty string/list — the
pinned schema still declares these fieldsnullable: falsein both
cases, so live server behavior was trusted over the schema's stale
claim (matching this project's owninstall_versionprecedent).
DhcpServer.domain/.domainsearchlist/.failover_peerip/.gateway/
.mac_allow/.mac_denyandDnsResolverSettings.sslcertref/
.tlsportare widened to also acceptNone; existing 2.8.1-shaped
fixtures (empty string/list) continue to validate unchanged. All 51
tools re-verified passing against the upgraded LAB after the fix; no
tool count change (51 unchanged), no new capability, no security
impact — a pure type-widening correctness fix. - Release-readiness audit (2026-08-21): three stale-documentation
findings. Two model docstrings
(firewall_nat_one_to_one_mapping.py,firewall_nat_outbound_mapping.py)
still said "Not yet cross-checked... verified (False)" despite both
Endpointsentries having beenverified=Truefor some time.
docs/PYPI_RELEASE.md's release checklist hardcoded "Confirm 42 READ
tools" — would have misdirected the owner during this very release;
replaced with a pointer to the live registry check instead of a
number that will go stale again next release.