# Bulletin and Controlled Prose routing Gate provides two disabled policies for the fleet's prose boundary. One validates a complete caller-owned bulletin section. The other carries a null routing request to Corpus. Neither policy reads a file, rewrites shared prose, starts a daemon, or registers a native hook. ```python from gate.admission import AdmissionKernel from gate.policies import BulletinSectionPolicy, ControlledProseRoutePolicy kernel = AdmissionKernel([BulletinSectionPolicy(), ControlledProseRoutePolicy()]) ``` Constructing this kernel activates nothing. A native adapter still has to prove the lifecycle, complete candidate, target identity, and supported effects described in [Action admission](admission.md). ## Bulletin section contract The adapter may identify the real fleet bulletin as the logical target `fleet.bulletin` only after it has proved the canonical file target and isolated the complete section owned by the caller. The candidate field is `bulletin_section`. Any other target or field makes the policy abstain, so an uncertain adapter cannot inspect or block another agent's section. One optional blank line may follow the H2 header. One final newline is also optional. All other lines are mandatory, single-line, ASCII values in this exact order: ```text ## - - ACTIVE doing: where: changes: yes | no ``` Duplicate, missing, unknown, reordered, empty, continued, or orphaned fields deny with that ASCII skeleton. `changes: no` is the complete no-change form; otherwise `yes` must be followed by one or more affected paths. Bare `yes`, `none`, and `maybe` deny. Non-ASCII typography, emoji, combining characters, and CJK-family characters also deny. The policy never repairs or moves text. Its feedback contains only stable issue classes and coordinates; receipts retain digests rather than the section or recovery text. ### Measured byte budget The 768-byte limit is calibrated, not a prose-quality claim. On 2026-09-02, the 12 active sections then present in `~/ai/bulletin.md` measured 235 bytes minimum, 431 median, 703 maximum, and 458.583 mean when each section was counted from its `##` header through its separating newline. The limit is the first 256-byte boundary above the observed maximum, leaving 65 bytes of headroom while making the three-value shape the primary brevity constraint. The replay was: ```sh LC_ALL=C awk ' /^## / { if (active) print bytes; active=1; bytes=length($0)+1; next } active { bytes+=length($0)+1 } END { if (active) print bytes } ' ~/ai/bulletin.md | sort -n | awk ' { value[NR]=$1; sum+=$1 } END { median = NR % 2 ? value[(NR+1)/2] : (value[NR/2]+value[NR/2+1])/2 printf "count=%d min=%d median=%.1f max=%d mean=%.3f\n", NR, value[1], median, value[NR], sum/NR } ' ``` This baseline measures real active entries before promotion. It does not show that those entries already conformed to the new field shape, and it does not authorize activation. Re-measure after a representative shaped trial before promoting the threshold fleet-wide. The optional policy's admission budget is the largest materializable Python candidate rather than a second, lower semantic limit. Its evaluator checks target and field identity first, then counts at most 769 UTF-8 bytes before returning the oversize denial. Consequently, adding bytes cannot turn the 768-byte rule into an optional kernel abstention, while an uncertain target or caller-owned field still abstains without scanning the candidate. ## Content-free Controlled Prose route `ControlledProseRoutePolicy` accepts only event `prose.route`, field `route_request`, value `None`, and the exact logical target `corpus.controlled_prose`. An adapter may mint that target only when it has evidence for target identity; native paths, suffixes, newlines, and document content in either candidate or target abstain. The policy emits an observation naming the same Corpus route and authority boundary. Gate therefore receives no prose bytes through this seam. The route is not an eligibility decision. Corpus retains every privacy ring, exclusion, parser, protected-span check, semantic review, compare-and-swap, undo, reins, and inbox rule. Public, private, and sealed labels all receive the same content-free route observation; Corpus decides what may proceed. ## Runtime survey and activation frontier The 2026-09-02 runtime survey found no Controlled Prose user unit or timer: ```text systemctl --user list-unit-files 'corpus-*prose*' # no rows systemctl --user list-timers 'corpus-*prose*' # no rows ``` Corpus exposes the `prose` and `prose-hygiene` console commands, but no prose daemon or timer was running. This change creates no second queue and does not activate either command. Native bulletin enforcement and any Controlled Prose service remain later, explicit rollout decisions with fresh adapter evidence and representative false-positive measurement. ```{eval-rst} .. automodule:: gate.policies.bulletin :members: ```