Requested deterministic constraints¶
Part of the termverify.transcript/v1 protocol.
Configuration table¶
run.started.payload.config has all of the following required members:
| Member | Required shape and v1 rule |
|---|---|
seed |
canonical decimal string representing an unsigned 64-bit integer: "0" or a nonzero digit followed by digits, with no leading zeroes |
clock |
{"mode": "manual", "initial_ms": non-negative integer} |
locale |
literal "C", or a well-formed RFC 5646 language tag |
timezone |
non-empty string naming the requested zone; only literal "UTC" may be reported as applied, so any other request is refused through unsupported (or the run fails before its receipt) |
terminal |
columns and rows positive integers; capabilities sorted unique strings |
filesystem |
{"mode": "sandbox", "root_id": string} |
network |
{"mode": "deny"} or {"mode": "allow-list", "allowed": [{"host": string, "port": integer 1–65535}]}; allowed is sorted by host then port and has no duplicates |
The configuration object and each defined nested object are closed except for
uninterpreted x- extensions. Raw command lines, environment variables, host
paths, and other invocation or machine identity are not deterministic-constraint
members and cannot be added as generic configuration fields at any nesting level.
Locale validation applies the RFC 5646 language-tag syntax only, including
normal, private-use, and fixed grandfathered forms plus the RFC prohibition on
duplicate variants and extension singletons. It does not consult the IANA
Language Subtag Registry, reject deprecated tags, or claim registry-backed
validity. RFC 5646 language tags are case-insensitive, while the separate C
sentinel is literal and case-sensitive. The codec preserves the caller's
spelling and case exactly; v1 performs no locale normalization or
preferred-value rewriting. Validation is therefore independent of the host
locale, installed locale data, environment, and network.
timezone is a plain non-empty string: the zone the run requests. There is no
timezone registry. V1 can only ever apply the literal UTC — applying a named
zone requires zone data this protocol deliberately never consults — so a closed
registry existed only to validate requests that must then be refused anyway, at
the cost of pinning v1 to one TZDB release with no registry-version selector in
the record (adversarial review 2026-07-24, finding P4; registry removed by owner
decision 2026-07-24, preserved in Git history). Any future reintroduction, when
a vertical actually demands non-UTC zones, is a fresh design with a version
selector rather than a revival of this one.
The codec preserves the requested spelling exactly and performs no alias, case,
or preferred-name normalization; it never consults ambient zoneinfo,
operating-system data, environment, or network state, so a transcript records
what was asked for. A non-empty string is all that either the schema or the
runtime requires of the request, and an x- extension cannot change what a
request means.
Truthfulness therefore rests on the receipt, never on the request's vocabulary.
A timezone request is not enforcement evidence: v1 receipts permit only literal
UTC as an effective value, and an adapter that cannot apply a requested zone
terminates through structured unsupported rather than fabricating one.
Requesting Mars/Olympus is valid and unhelpful in exactly the way requesting
Europe/Berlin is: both are refused, and the refusal is the record.
The configuration requests a constraint; it does not itself prove enforcement. What an adapter owes is a truthful receipt per constraint, never containment it does not have. The adapter-facing contract is:
- It applies each requested constraint through an explicit mechanism and
records which one. A constructive in-process runtime injects the requested
seed and manual clock through application-facing ports; a cooperation port
instead delivers the requested value to the subject through the channel named
in the delivery record, and does nothing further. Advancing manual time is
always an explicit
input.clock_advancedrecord, never a wall-clock wait. - It reports the effective value it actually applied, and configures the requested terminal dimensions and capabilities before the subject can observe them.
- It never records a stronger mechanism than it used. The filesystem and
network constraints in particular are applied at whatever tier the adapter
can support — an
os-tier sandbox root or socket denial where a mechanism exists, otherwisedelivered, where the requested policy is handed to the subject and honoring it is subject cooperation. Adelivered-tier receipt is not containment: no receipt, claim, or document may imply that it is (owner decision 2026-07-18,cooperation-tier-constraint-ports.md). - An adapter that cannot apply a requested constraint at any tier must record
it
unsupportedand terminate throughrun.unsupported. A verified run may includedelivered-tier constraints, and its constraint claims are no stronger than its weakest tier — which is why the tier is recorded per constraint rather than summarized per run. - It emits one
capability.resultfor each attempted constraint through the first unsupported constraint, withconstraint,status, and status-dependenteffective/tier/delivery/reasonmembers.statusis exactlyappliedorunsupported.appliedstates that the adapter carried out the constraint's application step and recorded the value it applied; the mandatorytierstates what that step was worth — atosandconstructivethe constraint itself is in force, while atdeliveredwhat was applied is the delivery, and whether the subject honors the delivered value is not observable. There is no third status: the status word never claims enforcement the tier disclaims, and a constraint the adapter can neither enforce nor deliver isunsupported. The first unsupported result terminates the transcript withrun.unsupportedand no input dispatch.
capability.result.payload.constraint is one of seed, clock, locale,
timezone, terminal, filesystem, or network; it follows the table order
above. For applied, effective is required and is the applied configuration
value, and tier is required and states the enforcement tier (below). For
unsupported, reason is required and the next record is the matching
run.unsupported terminal record.
Enforcement tiers¶
termverify.enforcement-tier/v1 is a closed, case-sensitive vocabulary owned
by this protocol version exactly like the key registries: exact membership, no
aliases or normalization, runtime validation authoritative.
Post-freeze membership or meaning changes require a new vocabulary version.
Its members, in decreasing claim strength:
| Tier | Claim |
|---|---|
os |
The constraint is applied by an operating-system mechanism at the subject boundary; evidence exists at the OS level. |
constructive |
The constraint is applied by construction of the controlled in-process runtime: the emitting port asserts that the subject reaches the constrained resource only through it. Stating it truthfully is part of the injected application's port contract. |
delivered |
The requested value was delivered to the subject, exactly as recorded, through the channel named in the delivery record; honoring it is subject cooperation. Nothing is enforced. |
Every applied capability result carries a mandatory tier. A
delivered-tier result additionally carries a mandatory delivery object
naming the channel through which delivery flowed; no other tier may carry a
delivery. The channel member is a closed set fixed by this protocol
version (like network.mode, not a registry): exactly one of the following
shapes.
channel |
Members | Claim |
|---|---|---|
spawn-env |
env (required, non-empty), cwd (required iff the constraint is filesystem, forbidden otherwise) |
The recorded environment variables (and, for filesystem, working directory) were placed into the subject's spawn environment. |
hello-config |
none beyond channel |
The constraint's run.started.config members — already recorded and validated in this transcript — were delivered to the subject in session.hello.config (termverify.control/v1). |
wire-message |
none beyond channel |
The value was delivered as a control-protocol message during the run; the protocol's own message records are the evidence. |
spawn-env member rules are unchanged: env maps non-empty variable names
(no = or NUL) to non-empty values (no NUL); cwd is a non-empty NUL-free
string. A channel tag names where delivery flowed; the claim never widens —
every channel claims delivery exactly as recorded, subject cooperation for
honoring, and nothing enforced.
Compatibility (amendment of 2026-07-20, owner decision on issue #173): the
pre-amendment bare form {"env": ..., "cwd"?} with no channel member
remains accepted and is normalized to {"channel": "spawn-env", ...} at the
ingest boundary; a form carrying env together with a channel other than
spawn-env is invalid. (The canonical spawn-env form itself carries both
channel and env, per the channel table above — it is the required
emitter output, not an invalid combination.) Emitters produce only the
channel-tagged form. Normalization is
performed by the codec's compat rules — named, pure, total,
normalize-toward-canonical functions applied between structural decode and
validation (_COMPAT_RULES in the runtime); they never relax acceptance,
and validation proper sees only the canonical form.
Membership in the
vocabulary is not evidence that an emitter exists: which tier a negotiation
path may state is fixed by the accepted cooperation-tier design and validated
fail-closed at runtime during receipt binding (an adapter's own terminal
negotiation may state os; ports injected into the terminal adapter may state
only delivered; ports negotiated by the direct adapter may state only
constructive). The same posture applies to channels: wire-message is
admitted before any emitter exists. A transcript records the stated tier but
cannot know the
emitting path, so transcript validation checks vocabulary membership and the
tier/delivery pairing only. A receipt never claims the subject honored a
delivered value, and no tier claims containment.
This leaves applications responsible for exposing controllable ports; it keeps the deterministic core independent from ambient time, randomness, terminal, filesystem, and network state.