context loading, path resolution, form state, dynamic rules, and provider-neutral assessment runner/cache boundary

This commit is contained in:
2026-05-04 13:52:29 +02:00
parent eccf1874fb
commit 8361f9ea45
29 changed files with 2809 additions and 65 deletions

View File

@@ -9,9 +9,9 @@ Markdown as the authoring surface and uses fenced YAML as a structured extension
for rules that need machine interpretation.
The first implementation is deterministic. It checks document type, fields,
sections, ordering, metric bands, and text assertions. Forms, context, and LLM
rubrics are represented in the contract vocabulary as extension points before
runtime adapters are added.
sections, ordering, metric bands, and text assertions. Runtime context, forms,
dynamic rules, and provider-neutral assessment requests are implemented as
extensions around the same contract vocabulary.
## Contract File Shape
@@ -112,10 +112,10 @@ fields, and metric bands. This is the bridge to later LLM rubrics: semantic
checks can become additional assessments without changing how failures are
reported.
## Forms And Context
## Forms, Context, And Runtime Rules
Field specs are the first step toward form-backed Markdown generation. Runtime
form handling should build on the same field vocabulary:
Field specs are the foundation for form-backed Markdown generation and
context-aware checks. Runtime form handling uses the same field vocabulary:
- `id`
- `type`
@@ -128,15 +128,25 @@ form handling should build on the same field vocabulary:
- `min` / `max`
- `min_length` / `max_length`
Dynamic requiredness, visibility, calculations, and prefill should be declared
as context-aware rules in later work. The contract should remain the source of
truth, while UI and generation layers act as adapters.
Runtime context can be supplied as local YAML or JSON:
```text
mkt contract check <document.md> --contract <contract.md> --context <context.yaml>
mkt contract form-state <document.md> --contract <contract.md> --context <context.yaml>
```
The runtime resolves fields in this order: document value, context source,
default, missing. Document values win over context and conflicts are diagnostics.
Dynamic rules support small deterministic `if` / `then` / `else` expressions
for requiredness, visibility, allowed values, calculated values, context
assertions, and dynamic section presence. See
`docs/runtime-context-forms-assessments.md`.
## LLM Assessment Extension
LLM-assisted checks should be declared as rubrics, scoped to document or section
roles. Core Markitect should not call a provider directly. A future adapter
should accept a provider-neutral request:
LLM-assisted checks are declared as rubrics, scoped to document or section roles.
Core Markitect does not call a provider directly. It creates provider-neutral
assessment requests for injected adapters:
- contract id and rule id
- document or section text
@@ -152,26 +162,11 @@ It should return:
- model/provider metadata
- diagnostics using the shared diagnostic model
## Deferred Runtime Work
The deterministic contract framework is ready now. The runtime engines are
deferred to `MKTT-WP-0005-runtime-context-and-assessment-engines.md`.
Pick that work up when one of these becomes true:
- contract checks need external user, project, or entity context
- generation needs reliable field prefill before rendering
- a UI or agent workflow needs form state, defaults, and dynamic requiredness
- deterministic section assertions are not enough and rubric-based semantic
assessment becomes necessary
The intended order is context and form runtime first, deterministic dynamic
rules second, LLM assessment execution third.
## CLI
```text
mkt contract validate <contract.md>
mkt contract check <document.md> --contract <contract.md>
mkt contract check <document.md> --contract <contract.md> [--context <context.yaml>]
mkt contract form-state <document.md> --contract <contract.md> [--context <context.yaml>]
mkt metrics <document.md>
```

View File

@@ -34,6 +34,8 @@ framework organizes how Markitect itself exposes and composes capabilities.
| `backend` | local SQLite index | snapshots/index/search storage |
| `reference-provider` | section, region, fence, line | address in, content units out |
| `validator` | schema, contract, section assertion | document/context in, diagnostics out |
| `runtime` | context loader, form state, dynamic rules | document/contract/context in, diagnostics and state out |
| `assessment-runner` | provider-neutral rubric execution | assessment request in, normalized result out |
| `template-engine` | deterministic templates | template/data in, Markdown out |
| `generation-adapter` | provider-neutral assisted generation | request in, generated candidate out |
| `cli-group` | cache, backend, ref, class | command descriptors or registration hook |

View File

@@ -72,7 +72,8 @@ This makes workflows useful without provider dependencies.
| `transform` | transformed `markdown`, operations, provenance. |
| `include` | include-resolved `markdown`, included paths, provenance. |
| `contract_stub` | generated contract stub Markdown. |
| `contract_check` | contract diagnostics and metrics. |
| `contract_check` | contract diagnostics, metrics, and optional runtime context results. |
| `form_state` | field values, origins, dynamic rule results, and diagnostics. |
| `assisted` | generated Markdown if a hook is supplied, otherwise skipped/diagnostic. |
## Data Bindings

View File

@@ -0,0 +1,220 @@
# 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:
```yaml
recipient:
name: Ada Lovelace
sender:
name: Markitect Team
```
or an envelope with metadata and schema:
```yaml
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.malformed`
- `runtime.context.schema_invalid`
- `runtime.context.schema_target_missing`
- `runtime.context.schema`
## Field Runtime
Field specs continue to live in the contract:
```yaml
fields:
recipient_name:
type: string
required: true
source: context.recipient.name
delivery_channel:
type: string
default: email
enum: [email, print]
```
Runtime resolution order is:
1. Manual document value from `path`, usually frontmatter.
2. Context value from `source` or `sources`.
3. Contract `default`.
4. 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:
```text
mkt contract check document.md --contract contract.md --context context.yaml
```
`mkt contract form-state` always emits the UI-neutral runtime view:
```text
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`, or `missing`
- 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:
```yaml
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:
- `exists`
- `equals` / `eq`
- `not_equals`
- `in`
- `contains`
- `matches`
- `gt`, `gte`, `lt`, `lte`
- `all`, `any`, `not`
Supported actions:
- `required` / `optional`
- `visible` / `hidden`
- `enabled` / `disabled`
- `allowed_values`
- `set`
- `assert`
- `sections`
Calculated values can reference runtime paths:
```yaml
then:
set:
contact_label: "${fields.sender_name.value} <${context.sender.email}>"
```
Context assertions use the same condition vocabulary:
```yaml
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:
```yaml
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`:
```yaml
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:
```yaml
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.

View File

@@ -188,7 +188,8 @@ First implementation step kinds:
| `transform` | Apply deterministic Markdown transforms. |
| `include` | Resolve include markers in Markdown. |
| `contract_stub` | Generate a Markdown stub from a contract. |
| `contract_check` | Check a Markdown document against a contract. |
| `contract_check` | Check a Markdown document against a contract, optionally with runtime context. |
| `form_state` | Evaluate UI-neutral field prefill, validation, and dynamic rules. |
| `assisted` | Provider-neutral assisted step boundary, optional by default. |
## Data Bindings

View File

@@ -35,7 +35,7 @@ and descriptions mirror the operational view.
| `MKTT-WP-0010` | complete | done | `MKTT-WP-0004`; task-level trigger: `MKTT-WP-0003-T006` | Content references, processors, explode/implode, weave/tangle, content classes, and migration examples are complete as the first WP-0010 extension layer. |
| `MKTT-WP-0007` | complete | done | `MKTT-WP-0006` | Advanced query and local index backend is complete: AST inspection, optional JSONPath, SQLite snapshots/metadata, FTS5 search, incremental refresh, and local index CLI. |
| `MKTT-WP-0013` | complete | done | `MKTT-WP-0003`, `MKTT-WP-0004`, `MKTT-WP-0006`, `MKTT-WP-0007`, `MKTT-WP-0010` | Internal extension framework is complete: characterization tests, canonical processing model, descriptors, registries, lifecycle callbacks, query-engine registry, built-in extension catalog, CLI command specs, and authoring guide. |
| `MKTT-WP-0005` | P2 | todo | `MKTT-WP-0003`, `MKTT-WP-0004` | Pick up when generation/form/context or semantic assessment pressure appears. |
| `MKTT-WP-0005` | complete | done | `MKTT-WP-0003`, `MKTT-WP-0004` | Runtime context, form state, dynamic rules, workflow integration, and provider-neutral assessment boundary are complete. |
| `MKTT-WP-0011` | complete | done | `MKTT-WP-0003`; task-level triggers: `MKTT-WP-0010-T001`, `MKTT-WP-0010-T005` | Markdown dataflow workflow layer is complete: workflow standard, source collectors, binding model, deterministic steps, assisted boundary, safe outputs, CLI, docs, and examples. |
| `MKTT-WP-0009` | P2 | todo | `MKTT-WP-0006` | Establish access-control gateway before security-sensitive cache/context use. |
| `MKTT-WP-0012` | P3 | todo | `MKTT-WP-0004`, `MKTT-WP-0010`, `MKTT-WP-0011` | Future Quarkdown-inspired document function layer: reusable Markdown-native function calls over processors, references, contracts, workflows, and later assisted steps. |