5.4 KiB
Runtime Context, Forms, Rules, And Assessments
Date: 2026-05-04
Purpose
The runtime layer turns contract extension points into executable behavior while keeping the deterministic contract framework intact. Static checks still handle document type, sections, assertions, and metric bands. Runtime checks add external context, field prefill, UI-neutral form state, dynamic rules, and a provider-neutral assessment protocol.
The layer is deliberately local-first. Core Markitect reads YAML or JSON context files and runs deterministic rules. Network calls, application lookups, and LLM providers belong behind adapters.
Context Files
Runtime context can be a raw YAML/JSON mapping:
recipient:
name: Ada Lovelace
sender:
name: Markitect Team
or an envelope with metadata and schema:
metadata:
case_id: case-42
schema:
type: object
required: [recipient, sender]
context:
recipient:
name: Ada Lovelace
sender:
name: Markitect Team
The value under context is bound as context in field sources and dynamic
rules. schema validates the full context object. schemas can validate named
objects individually.
Malformed context and schema failures produce normal diagnostics:
runtime.context.malformedruntime.context.schema_invalidruntime.context.schema_target_missingruntime.context.schema
Field Runtime
Field specs continue to live in the contract:
fields:
recipient_name:
type: string
required: true
source: context.recipient.name
delivery_channel:
type: string
default: email
enum: [email, print]
Runtime resolution order is:
- Manual document value from
path, usually frontmatter. - Context value from
sourceorsources. - Contract
default. - Missing.
Manual document values win over context. If both exist and differ, Markitect
emits runtime.field.conflict as a warning by default. A field can set
conflict: error to make that stricter. Multiple context sources with distinct
values produce runtime.field.ambiguous.
mkt contract check uses runtime evaluation only when --context is supplied:
mkt contract check document.md --contract contract.md --context context.yaml
mkt contract form-state always emits the UI-neutral runtime view:
mkt contract form-state document.md --contract contract.md --context context.yaml
Form State
Form state is not a UI framework. It is a stable contract that future UIs, agents, generators, and workflow steps can render:
- field id
- value
- origin:
manual,prefilled,defaulted,calculated, ormissing - required/optional
- visible/hidden
- enabled/disabled
- allowed values
- diagnostics
- metadata
Hidden fields are not required unless a future adapter explicitly asks for hidden validation. This matches practical form behavior and avoids punishing authors for data that the current context made irrelevant.
Dynamic Rules
Rules are deterministic YAML. They use a deliberately small condition language:
rules:
- id: postal-address-for-print
if:
path: fields.delivery_channel.value
equals: print
then:
required: [postal_address]
visible:
postal_address: true
else:
hidden: [postal_address]
Supported condition operators:
existsequals/eqnot_equalsincontainsmatchesgt,gte,lt,lteall,any,not
Supported actions:
required/optionalvisible/hiddenenabled/disabledallowed_valuessetassertsections
Calculated values can reference runtime paths:
then:
set:
contact_label: "${fields.sender_name.value} <${context.sender.email}>"
Context assertions use the same condition vocabulary:
assert:
path: context.sender.email
matches: "@example\\.com$"
message: Sender email must come from example.com.
severity: warning
Dynamic section rules are intentionally narrow. They can require, recommend, discourage, or forbid section specs already declared in the contract.
Assessment Protocol
Rubrics remain provider-neutral contract declarations:
rubrics:
- id: tone-fit
scope: section.body
criteria: The body should match the recipient relationship.
threshold: 0.75
Core Markitect turns rubrics into AssessmentRequest objects and normalizes
adapter results into AssessmentResult and diagnostics. It does not call an LLM
provider directly. The cache key includes contract id, rule id, scope, text,
criteria, context, structured inputs, threshold, provider, model, and metadata.
Adapters can be injected from workflows, applications, or tests. A transparent in-memory cache exists for tests and short runs; persistent storage remains a backend concern.
Workflow Integration
Workflow contract_check steps accept context:
steps:
- id: check-letter
kind: contract_check
document: letter.md
contract: letter.contract.md
context: letter.context.yaml
Workflow form_state steps expose the runtime state as a step result:
steps:
- id: form
kind: form_state
document: letter.md
contract: letter.contract.md
context: letter.context.yaml
This keeps workflow orchestration separate from the runtime engine. The runtime engine answers "what does this contract imply in this context"; the workflow engine decides when to run it and where to send the output.