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.

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.

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:

## <task> - <agent> - ACTIVE

doing: <one line>
where: <one line>
changes: yes <paths> | 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:

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:

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.

Deterministic bulletin-shape checks and content-free prose routing.

The bulletin policy accepts one complete caller-owned section under a logical target identity. It never reads or rewrites the shared bulletin. The Controlled Prose policy routes only a null request plus target identity; document bytes remain outside Gate and under Corpus authority.

class gate.policies.bulletin.BulletinIssue(kind: BulletinIssueKind, line: int, column: int = 1)#

One validation failure located without retaining source content.

diagnostic() → str#

Return one bounded ASCII diagnostic.

class gate.policies.bulletin.BulletinIssueKind(*values)#

Stable, content-free bulletin validation classes.

class gate.policies.bulletin.BulletinSectionPolicy#

Validate one complete, caller-owned fleet bulletin section.

evaluate(attempt: Attempt) → Proposal#

Validate the section without reading or mutating the shared file.

class gate.policies.bulletin.ControlledProseRoutePolicy#

Route a null Markdown request to Corpus without receiving document bytes.

evaluate(attempt: Attempt) → Proposal#

Observe an eligible route request while leaving eligibility to Corpus.

gate.policies.bulletin.inspect_bulletin_section(value: str) → tuple[BulletinIssue, ...]#

Return deterministic shape and character findings for one complete section.