mirror of
https://github.com/openprose/prose.git
synced 2026-09-19 05:55:05 +08:00
f12dcda4d8
Ships @openprose/reactor 0.3.0, @openprose/reactor-cli 0.2.0, @openprose/reactor-devtools 0.2.0: the Reactor harness (compile-once-intelligent then dumb reconciler, content-addressed receipts, cost scales with surprise) with the distilled ideal public API — curated front door, full @openai/agents passthrough, one typed handle, one Substrate, unified observe, branded ids, and additive forward seams for the fixpoint.
611 lines
35 KiB
Markdown
611 lines
35 KiB
Markdown
# OpenProse Reactor Pattern
|
|
|
|
###### How to write OpenProse for a Reactor-class harness — the language layer beneath evented reconciliation.
|
|
|
|
The OpenProse corpus divides labor exactly, and each document maps to what
|
|
ships:
|
|
|
|
- [01-Language.md](./01-Language.md) — **the Language & Framework**, bundled as
|
|
the **SKILL**: syntax, kinds, sections, compile model, std/co, CLI surface.
|
|
- [02-ReactorHarness.md](./02-ReactorHarness.md) — **the Reactor
|
|
Harness**, bundled as the **CLI/Server**: the runtime control architecture
|
|
(loop, invariants, the reconciler, memoization, forecast, receipts, composition). It
|
|
answers _what the runtime must do_.
|
|
- [03-ReactorPattern.md](./03-ReactorPattern.md) — **this
|
|
document, the Reactor-Native Authoring Pattern**: **SKILL-bundled but
|
|
harness-governed**. Where the Harness doc says what the runtime does, this
|
|
says **what the author writes** so the runtime can do it. It bridges the
|
|
Language doc and the Harness doc and is the definitive guide to writing
|
|
`*.prose.md` for a Reactor-class harness.
|
|
- [ReactorFeedback.md](../history/ReactorFeedback.md) — **the
|
|
decision log**, not shipped: the dialectic that produced the Harness doc;
|
|
the clean statements live in the docs above and it does not repeat them.
|
|
- [00-Tenets.md](./00-Tenets.md) — **the constitution**. When any
|
|
document tensions with a tenet, the tenet wins.
|
|
|
|
The relationship is the same as the one between a language reference and an
|
|
effective-style guide. The harness doc tells you the machine has memoization,
|
|
forecast-gated quiescence, deterministic commit-gating, and receipt composition.
|
|
This doc tells you how to write contracts so those mechanisms actually engage
|
|
instead of degrading to "cron plus a prompt."
|
|
|
|
This file has three parts, mirroring the harness doc:
|
|
|
|
1. The ideal Reactor-native authoring pattern.
|
|
2. What the OpenProse skill implements today.
|
|
3. What must change in the skill before the pattern is fully authorable.
|
|
|
|
The single most important principle, stated once up front so the rest is read
|
|
in its light:
|
|
|
|
> **The Reactor paradigm does not change OpenProse syntax. It inverts which
|
|
> kind is the program.** Every section, kind, and keyword the pattern needs
|
|
> already exists. What changes is doctrine: the responsibility is the
|
|
> top-level authored object, the render is where the work happens (there is no
|
|
> separate fulfillment system), and two contract sections (`### Maintains` and
|
|
> `### Continuity`) carry a cost-and-reconciliation obligation they did not
|
|
> visibly carry before.
|
|
|
|
---
|
|
|
|
## I. The Ideal Reactor-Native Authoring Pattern
|
|
|
|
### The inversion
|
|
|
|
`01-Language.md` settles the mental model: the **responsibility is the program**.
|
|
A standing goal, written as durable intent, is the top-level authored object;
|
|
everything else is derived from it.
|
|
|
|
```text
|
|
The responsibility is the program.
|
|
A gateway is how the world reaches it.
|
|
A function is a helper one render calls; the DAG is how responsibilities compose.
|
|
Forme, the canonicalizer, and the VM are the substrate, never the unit of authoring.
|
|
```
|
|
|
|
The authoring consequence: **you do not start by writing a system. You start by
|
|
writing one sentence of durable intent and what makes it true** — a `### Goal`
|
|
and a `### Maintains`. A responsibility is _served_, not _run_, but that is not a
|
|
limitation: "not directly runnable" means "continuously reconciled," which is the
|
|
entire point. The render of a single responsibility still runs standalone
|
|
(language sovereignty), so there is no lesser, non-executable artifact here.
|
|
|
|
### The canonical contract
|
|
|
|
A Reactor-native unit of work is, at its smallest, **one file**: a
|
|
`kind: responsibility` whose `### Maintains` declares the truth to keep current.
|
|
It grows only as the work demands:
|
|
|
|
| File | `kind:` | What the author is really writing |
|
|
| --- | --- | --- |
|
|
| The standing goal | `responsibility` | One `### Goal` sentence + the `### Maintains` world-model that makes it true (facets, canonicalization, postconditions) |
|
|
| Event ingress | `gateway` | How and when the world is allowed to wake the loop |
|
|
| A helper | `function` | A called, ephemeral computation a render invokes — `### Parameters` → `### Returns` |
|
|
|
|
There is no separate "fulfillment system," no "sense service," no "verdict
|
|
service," and no "ledger service": the render *is* the fulfillment, the
|
|
canonicalizer *is* how change is sensed, `gateCommit` *is* the admissibility check, and
|
|
the signed receipt ledger *is* the storage — all owned by the harness, not
|
|
authored. A reader who understands the responsibility understands the program;
|
|
the rest is _how_, and may change without the intent changing (invariant 1, at
|
|
authoring time).
|
|
|
|
### Authoring derived from the invariants
|
|
|
|
Each harness invariant produces a concrete, checkable authoring rule. This
|
|
table is the spine of the pattern; the prose after it only elaborates.
|
|
|
|
| Harness invariant | Authoring rule it imposes |
|
|
| --- | --- |
|
|
| 1. Markdown is intent | The responsibility carries all semantic weight. Never push intent into a prompt or a tool config. If it matters, it is in `### Goal` / `### Requires` / `### Maintains`. |
|
|
| 2. Materiality is compiled and shared | Declare *what counts as a material change* as natural language inside `### Maintains` — which fields matter, how they normalize, where the facets fall. The compile phase lowers that into a deterministic canonicalizer; you state the materiality, not the hash. |
|
|
| 3. Adapters are the only reason homes differ | Author no host-specific logic in contracts. Declare needs in `### Tools` / `### Environment` by name only. The same contract must run local and cloud. |
|
|
| 4. Activations are bounded | Never write a render that assumes it keeps running. No "while true," no in-session waiting for the next event. Continuity lives in the receipt ledger, not a session. |
|
|
| 5. Cost scales with surprise | Write `### Maintains` so "did anything material change?" is **cheaply decidable** — give the truth a stable content identity and facet it so an unrelated change wakes nobody. Declare freshness (`valid_until`) in `### Continuity` so silent staleness still wakes the node. This is the rule authors most often violate. |
|
|
| 6. The commit gate is deterministic | State satisfaction as **postconditions inside `### Maintains`** — deterministic where you can express a validator, self-attested by the render where it is semantic. There is no separate judge and no `### Criteria`. |
|
|
| 7. Receipts are content-addressed | Trust the harness's signed receipt ledger as the audit / composition / exit unit. Do not hand-roll a scratch log. |
|
|
| 8. State is replayable and exitable | Keep all durable truth in the responsibility's `### Maintains` world-model, in plain structured records. A reader must be able to take the contract and its trail to another harness. |
|
|
|
|
### Rule 1 — `### Goal` is one standing-intent sentence
|
|
|
|
A goal is a state that should remain true, not a task or a deliverable. Not
|
|
"triage the inbox," not "produce a report," but an invariant: "the research inbox
|
|
is deduplicated, prioritized, and converted into action."
|
|
|
|
The test is no longer "could a judge score it" — there is no judge. The test is:
|
|
**can you name the maintainable truth and declare its shape in `### Maintains`?**
|
|
If the sentence describes an _activity_ rather than a _state_, rewrite it until
|
|
it describes a state. A sentence whose truth has nothing observable to maintain
|
|
against is the highest-value early signal: the first render fails, its receipt
|
|
names the gap, and the contract author hears about it — front-loaded, then
|
|
silent.
|
|
|
|
### Rule 2 — `### Continuity` declares the wake source; `### Maintains` carries the materiality
|
|
|
|
These were once one rule; they are two jobs, and conflating them is the most
|
|
common authoring mistake.
|
|
|
|
`### Continuity` answers **when, beyond an input change, this node should
|
|
re-render**:
|
|
|
|
- **Input-driven (default).** The node wakes when a subscribed `### Requires`
|
|
facet moves. You write nothing extra.
|
|
- **Self-driven.** The truth goes stale on its own. Declare a `valid_until`
|
|
freshness window — "a stargazer count older than one business day is stale."
|
|
When it lapses, the continuity clock mechanically moves the facet's fingerprint
|
|
and wakes the node; you do not hand-write a cron.
|
|
- **External-driven.** A `kind: gateway` turns an ingress event (webhook, queue,
|
|
schedule) into a wake.
|
|
|
|
The *memoization* half — what counts as a material change, and whether "nothing
|
|
changed" is cheaply decidable — belongs in **`### Maintains`**, not here. Write
|
|
`### Maintains` so an unchanged world produces an unchanged fingerprint: give the
|
|
truth a stable content identity (a content hash, a max-timestamp, a revision) and
|
|
facet it so an unrelated change wakes nobody. If the only way to know whether
|
|
anything changed is to redo the full expensive render, you have written a
|
|
contract whose cost scales with the clock, not surprise — say so deliberately
|
|
(the node will run at freshness cadence), exactly as projection-only is a
|
|
deliberate choice rather than a degenerate Reactor.
|
|
|
|
### Rule 3 — satisfaction is a postcondition in `### Maintains`, not a `### Criteria` judge
|
|
|
|
There is no `### Criteria` and no judge. State what "satisfied" means as
|
|
**postconditions inside `### Maintains`**:
|
|
|
|
- **Deterministic where you can express it.** "The release-notes file's last
|
|
commit is newer than the latest merged PR touching `src/`" compiles into a
|
|
validator the harness runs at commit. If it fails, the render commits nothing.
|
|
- **Self-attested where it is semantic.** Where the obligation cannot be reduced
|
|
to a validator, the render must attest it satisfied its own `### Maintains`
|
|
before it signs. `gateCommit` fails closed: no attestation, no commit.
|
|
|
|
When the truth genuinely has *nothing observable to maintain against*, the render
|
|
cannot satisfy its postcondition and writes a `failed` receipt naming the gap —
|
|
routed to the contract author. Author postconditions *expecting* this on the
|
|
first few activations; that front-loading is the promise, not a defect. There is
|
|
no `up`/`drifting`/`down`/`blocked` status to encode and no "undecidable" enum —
|
|
the `failed` receipt and its reason carry it.
|
|
|
|
### Rule 4 — `### Invariants` draws the actuation boundary
|
|
|
|
`### Invariants` (the section that absorbs the old `### Constraints`) is where the
|
|
author quarantines world-mutation — the authoring-time expression of the
|
|
render/commit split: a render may act, but only the canonicalized published truth
|
|
re-enters the memo, and `### Invariants` bounds what the render may touch.
|
|
|
|
Two boundary shapes recur:
|
|
|
|
- **Full Reactor.** The render may mutate the world (send the email, update the
|
|
briefing, write the register). `### Invariants` bounds _how_ (rate, scope,
|
|
prohibited actions, "leave the final send to a human").
|
|
- **Projection-only Reactor.** The author forbids all world-mutation except
|
|
writing the published truth itself: an observe-only overseer, a dashboard that
|
|
must stay true, an audit that watches but never touches. Say so explicitly:
|
|
"the only writable surface is the published truth; never modify, signal, or
|
|
write into the observed system."
|
|
|
|
A projection-only contract is not a degenerate Reactor. It keeps every cost and
|
|
audit property; it simply declines the reconcile-the-world payoff. Choose it
|
|
deliberately, not by backing into it.
|
|
|
|
### Rule 5 — write `### Maintains` so the harness can memoize
|
|
|
|
Authors most often write the anti-pattern: a render that re-derives everything
|
|
every time. The fix is not a service decomposition — it is shaping `### Maintains`
|
|
so the dumb reconciler can skip:
|
|
|
|
1. **Give the truth a stable content identity.** The canonicalizer fingerprints
|
|
the published truth; make sure an unchanged world yields an unchanged
|
|
fingerprint (drop volatile fields — a re-poll timestamp, a request id — from
|
|
materiality). This is what lets the reconciler skip *before* any render runs
|
|
(quiescence behavior 1).
|
|
2. **Facet the truth.** Split `### Maintains` into `####` parts so a consumer
|
|
subscribing to one facet is not woken by a change in another (quiescence
|
|
behavior 3). A diamond reconverges to a single wake.
|
|
3. **Declare freshness.** Put `valid_until` windows in `### Continuity` so silent
|
|
staleness still wakes the node (quiescence behavior 2).
|
|
|
|
Variable-depth work, where you genuinely need it, is ordinary control flow
|
|
*inside the one render* — a `call` to a `function` for an expensive sub-step,
|
|
gated by an `if` in `### Execution`. It is not a "judge tier" and not an
|
|
autowired service graph.
|
|
|
|
### Rule 6 — composition is subscribing to an upstream facet, not a new primitive
|
|
|
|
"Responsibility B depends on responsibility A" needs no new syntax. B names the
|
|
upstream facet in `### Requires`; Forme matches it to A's `### Maintains` facet
|
|
and draws the subscription edge. B's render wakes on A's receipt when that
|
|
facet's fingerprint moves — identical to consuming a webhook. Two authoring
|
|
obligations make it safe:
|
|
|
|
- **Reference, don't embed.** B's `### Requires` names A's responsibility id /
|
|
facet as a declared subscription, not a copied value.
|
|
- **Pin revision and trust.** For cross-trust-domain composition, pin which
|
|
revision of A you accept and an acceptable signer set; unpinned composition is
|
|
a supply-chain attack the author closes, not the runtime. (In v1 "signed" is
|
|
meaning-layer chain-consistency; the cryptographic signer is a deferred
|
|
milestone.)
|
|
|
|
Freshness needs no special authoring: each facet carries its own `valid_until`,
|
|
so a stale upstream facet's fingerprint lapses and wakes B through the ordinary
|
|
path. There is no transitive-freshness function to shape and no per-cycle
|
|
staleness comparison to hand-write.
|
|
|
|
This is how a downstream responsibility consumes an upstream one — a subscription
|
|
edge, not a special case.
|
|
|
|
### Patterns that are Reactor-native
|
|
|
|
The std pattern library is use-case agnostic, but a subset recurs in
|
|
Reactor-native contracts and should be the author's default vocabulary:
|
|
|
|
| Pattern | Reactor-native role |
|
|
| --- | --- |
|
|
| `fan-out`, `map-reduce` | Sensing a wide world cheaply, in parallel, inside one render |
|
|
| `guard` | A precondition gate before an expensive `call` or a world-mutating step |
|
|
| `worker-critic`, `proposer-adversary` | A built-in check a render runs before it attests and commits |
|
|
| `oversight` | The actor / observer / arbiter split — the canonical projection-only shape |
|
|
|
|
These coordinate `call`s to `function`s *inside a render*; none is a separate
|
|
node, a judge tier, or an autowired graph. Depth — running a critic only on the
|
|
uncertain branch — is ordinary `### Execution` control flow, not a
|
|
confidence-gated judge ensemble.
|
|
|
|
### A worked example: the competitor-activity monitor
|
|
|
|
The running example across the harness and world-model specs: keep a current
|
|
picture of a set of competitors, where downstream consumers care about
|
|
*different parts* of that picture and should wake only when their part moves.
|
|
|
|
**The responsibility** (the whole program):
|
|
|
|
```markdown
|
|
---
|
|
name: competitor-activity-monitor
|
|
kind: responsibility
|
|
id: 067NC4KG01RG50R40M30E20918
|
|
---
|
|
|
|
### Goal
|
|
|
|
The activity of the tracked competitors — their funding, hiring, and product
|
|
launches — is current.
|
|
|
|
### Requires
|
|
|
|
- `competitors`: the watchlist (names + domains) this monitor tracks.
|
|
|
|
### Maintains
|
|
|
|
A `competitor-activity` world-model with three independently-subscribable parts:
|
|
|
|
#### funding
|
|
Rounds, amounts, investors, and dates. Material: a new or changed round.
|
|
Immaterial: re-ordering, prose phrasing, the timestamp of the last poll.
|
|
|
|
#### hiring
|
|
Open roles and headcount signals by function. Material: a role appears or
|
|
closes, or headcount crosses a band. Immaterial: list order, exact view counts.
|
|
|
|
#### product-launches
|
|
Announced launches and ship dates. Material: a new launch or a moved date.
|
|
|
|
Postcondition: every entry cites the source it was derived from; an entry with
|
|
no observable source is not committed (the render attests this).
|
|
|
|
### Continuity
|
|
|
|
- Input-driven: wake when the `competitors` watchlist changes.
|
|
- Self-driven: each part carries a `valid_until` of +1 business day; when it
|
|
lapses, that part is re-checked against the world.
|
|
|
|
### Invariants
|
|
|
|
- Read-only on the outside world: never contact a competitor or alter a source.
|
|
- The only writable surface is the `competitor-activity` world-model.
|
|
|
|
### Tools
|
|
|
|
- cli:web-fetch
|
|
- cli:fs-read
|
|
```
|
|
|
|
**A downstream consumer** subscribes to one facet, and wakes only on that facet:
|
|
|
|
```markdown
|
|
---
|
|
name: weekly-competitor-brief
|
|
kind: responsibility
|
|
id: 067NC4KG01RG50R40M30E20919
|
|
---
|
|
|
|
### Requires
|
|
|
|
- `funding` from `competitor-activity-monitor` # subscribes to ONE facet
|
|
|
|
### Maintains
|
|
|
|
A short brief summarizing the latest funding activity for the watchlist.
|
|
|
|
### Continuity
|
|
|
|
- Self-driven: a `valid_until` of +7 days, so the brief refreshes weekly even
|
|
if funding stays quiet.
|
|
```
|
|
|
|
What the harness does with this, for free:
|
|
|
|
- A re-poll that finds **no material funding change** produces an unchanged
|
|
`funding` fingerprint, so the monitor writes a `skipped` receipt and the brief
|
|
never wakes — *cost scales with surprise.*
|
|
- A new **hiring** signal moves only the `hiring` fingerprint; the brief
|
|
subscribes to `funding`, so it stays asleep — *facets make subscription
|
|
selective.*
|
|
- When `funding`'s `valid_until` lapses, the continuity clock moves its
|
|
fingerprint and wakes the monitor with a zero-token self-receipt; if the
|
|
re-check finds real news, *that* propagates to the brief.
|
|
- A render that cannot cite a source for an entry fails its postcondition,
|
|
commits nothing, and leaves a `failed` receipt — the prior truth stands.
|
|
|
|
No `kind: system`, no `### Services`, no judge, no ledger service: the render
|
|
maintains the world-model, the canonicalizer senses change, `gateCommit` gates
|
|
the commit, and the signed receipt ledger is the trail.
|
|
|
|
### Anti-patterns
|
|
|
|
Each is the natural non-Reactor instinct and why it breaks an invariant:
|
|
|
|
- **Modeling the work as a graph of services instead of one responsibility.**
|
|
Inverts the model; the wiring becomes the source of intent (breaks
|
|
invariant 1). Start from the `### Maintains` truth, not a system.
|
|
- **A render with a `loop until done` that waits for events in-session.** That
|
|
is a long-running agent loop, not bounded activations (breaks invariant 4).
|
|
- **A `### Maintains` with no material/immaterial split, so every re-poll looks
|
|
changed.** The canonicalizer's fingerprint moves every cycle; the reconciler
|
|
can never skip and cost scales with the clock (breaks invariant 5). This is the
|
|
most common and most expensive mistake.
|
|
- **A contract whose only "did anything change" test is the full render, written
|
|
as if it memoizes.** Not an invariant-5 _correctness_ break (the continuity
|
|
clock still makes it safe) but a false cost claim. The Reactor-native form names
|
|
the absence of a cheap identity and accepts freshness-cadence cost
|
|
deliberately — exactly as projection-only is a deliberate choice, not a
|
|
degenerate Reactor.
|
|
- **Hand-coding a cadence in `### Execution`** instead of declaring the wake in
|
|
`### Continuity` (an input subscription or a `valid_until`). It hides the
|
|
schedule from the harness and defeats forecast-paced quiescence (breaks
|
|
invariant 5).
|
|
- **Putting volatile fields in `### Maintains`** — a poll timestamp, a request
|
|
id, a re-ordered list — so the fingerprint moves on noise (breaks invariant 5).
|
|
- **Consuming another responsibility's value by copying it into the contract.**
|
|
Not a verifiable, revision-pinned subscription; a supply-chain hole (breaks
|
|
invariants 6/7). Name the facet in `### Requires` instead.
|
|
- **"Swarm of subagents that continuously watches."** The cron-plus-prompt shape
|
|
the Reactor replaces. The Reactor-native form is: a subscribed input or a
|
|
lapsed `valid_until` wakes one bounded render; nothing watches in between.
|
|
|
|
### Precedence for authors
|
|
|
|
When authoring rules tension, follow the harness precedence stack:
|
|
|
|
```text
|
|
correctness > safety > cost > interrupt-minimization
|
|
```
|
|
|
|
If a correct, safe contract surfaces more `failed` receipts to the author early,
|
|
accept them. If making a contract cheaper would make it unsafe (dropping a
|
|
postcondition on a high-stakes goal so it commits without checking), pay the
|
|
cost. Silence is a target, never a constraint the other rules bend around.
|
|
|
|
---
|
|
|
|
## II. What The OpenProse Skill Implements Today
|
|
|
|
The current model in Part I — intelligent compile (per-node canonicalizer +
|
|
Forme topology + postcondition validators, fired only on a contract-set change)
|
|
over a dumb deterministic run (compare `(contract_fingerprint, input_fingerprints)`
|
|
→ skip / render / `gateCommit` / propagate) — is the model the shipped skill
|
|
authors against. This section is the conformance ledger: what the skill routes
|
|
today, measured honestly against that pattern.
|
|
|
|
The reference harness backing the skill is the three packages that ship
|
|
together — `@openprose/reactor` (the engine SDK, `0.2.0`), `@openprose/reactor-cli`
|
|
(command `reactor`, `0.1.0`, twelve commands), and `@openprose/reactor-devtools`
|
|
(the replay viewer, `0.1.0`). The skill's `responsibility-runtime.md` and
|
|
`concepts/{responsibility,reactor}.md` are already written to this model; the
|
|
retired judge/verdict/status/pressure/fulfillment vocabulary is gone from the
|
|
authoring surface, not merely deprecated.
|
|
|
|
### The authoring surface that already exists
|
|
|
|
The headline finding still holds: **the Reactor-native pattern requires no new
|
|
syntax** — but the syntax it requires is the *current* one. The skill routes the
|
|
kinds and sections Part I names, and only those.
|
|
|
|
| Pattern element | Skill support today |
|
|
| --- | --- |
|
|
| `kind: responsibility` with `### Goal` / `### Requires` / `### Maintains` / `### Continuity` / `### Invariants` (+ `### Tools` / `### Shape` / `### Runtime`) | Present and canonical (`concepts/responsibility.md`, `contract-markdown.md`); `id:` is tooling-minted and stable across `name:`/filename renames |
|
|
| `kind: function` with `### Parameters` / `### Returns` — a stateless called helper (the former `service`) | Present; run as a lone render with no Forme phase |
|
|
| `kind: gateway` — sugar for an external-driven responsibility; Forme's entry-point set | Present; `reactor serve` registers it and stages ingress (fetch → extract → stage + a durable idempotency cursor) |
|
|
| `kind: pattern` / `kind: test` | Present; patterns expand at compile time, tests route to `prose test` / `reactor` test semantics |
|
|
| Facets: `####` parts under `### Maintains` — name = fingerprint unit + subscription symbol; atomic default | Present and **facet-granular propagation is live in production** (the v2 named-parts model); a downstream subscribed to one facet does not wake when another moves |
|
|
| `### Maintains` as the world-model schema doing four jobs (type, canonicalization spec, facets, postconditions) | Present; the postconditions are the folded-in `### Criteria`, compiled to validators |
|
|
| `### Continuity` as the structural wake-source declaration (input / self / external) | Present; self-driven recheck and the gateway entry point are both wired (Phase 4) |
|
|
| `### Execution` ProseScript for variable-depth work inside one render | Present — an `if`-gated `call` to a `function` is the depth mechanism, not a judge tier |
|
|
| Compile as SKILL-loaded sessions (Forme / canonicalizer / postcondition) → deterministic lowering → content-addressed IR cache | Present; a `.prose` set mounts without hand-authoring via a true semantic `Requires ↔ Maintains` match |
|
|
| Run: dumb reconciler — memo-skip on unmoved `(contract_fp, input_fp)`, single-flight + coalescing, failure = no-commit, propagate only on a `rendered` moved fingerprint | Present (`@openprose/reactor`); restart-survival proven (truth + ledger survive a fresh process) |
|
|
| `gateCommit`: deterministic postcondition validators + render self-attestation of `### Maintains`; receipt status in `{rendered, skipped, failed}` | Present; no judge, no verdict, no status enum |
|
|
| Content-addressed, chain-verifiable receipt ledger; cost = `tokens.fresh` vs `tokens.reused` + `surprise_cause` | Present (`reactor receipts` chain-verifies and tamper-detects; the devtools meter renders "cost scales with surprise") |
|
|
| Composition: a downstream responsibility names an upstream facet in `### Requires`; Forme draws the subscription edge | Present; the reconciler reads the topology `edges` to resolve propagation |
|
|
|
|
The skill can already express a Reactor-native program end to end *in the current
|
|
model*: one responsibility with a faceted `### Maintains`, a gateway for ingress,
|
|
a `function` helper for an expensive sub-step, a projection-only or full
|
|
actuation boundary in `### Invariants`, postcondition-gated commit, and a
|
|
composition edge that is a real subscription rather than a copied value.
|
|
|
|
### Current authoring limits
|
|
|
|
Part I states the pattern as an unqualified north star. This is where authoring
|
|
reality is honest, rule by rule.
|
|
|
|
| Authoring rule (Part I) | State | What the author must currently know |
|
|
| --- | --- | --- |
|
|
| 1. Intent lives in the responsibility | Conformant | Fully authorable today |
|
|
| 2. Materiality stated semantically in `### Maintains` | Conformant (authoring) | The author states materiality in prose; it is lowered to a deterministic canonicalizer. The lowering runs **only spec→code** — a compile session reads the `### Maintains` prose and emits the canonicalization spec, which the deterministic producer compiles. There is no `.prose` *parser*; compile is sessions, not a grammar |
|
|
| 3. No host-specific contract logic | Conformant | `### Tools` (`cli:` / `mcp:`) and `### Environment` are name-only; resolution is fail-closed and never installs or contacts at compile |
|
|
| 4. Bounded activations | Conformant | Idiomatic; the "loop until done" anti-pattern is author error, not a skill gap |
|
|
| 5. Written for memoization / variable depth | Conformant | The reconciler's skip on `(contract_fp, input_fp)` is live (cost scales with surprise, including an immaterial-churn re-poll that still skips); facet selectors are live; depth is an `if`-gated `call` in `### Execution`. The author's leverage is real today |
|
|
| 6. Composition via a subscribed upstream facet | Conformant (meaning-layer) | A downstream names the upstream facet in `### Requires` and Forme wires the edge; receipts are content-addressed and the chain is verifiable. The **cryptographic** signer is a null-state — v1 "signed" is meaning-layer chain-consistency, not a byte-hash — so cross-trust-domain *pinning to a signer set* is not yet enforceable |
|
|
| 7. Receipts as the audit / composition / exit unit | Conformant | The ledger is flat `<state-dir>/receipts.json`, content-addressed, chain-verifiable; `cost` (fresh/reused/surprise_cause) and `status` are first-class. No hand-rolled scratch log is needed |
|
|
| 8. Replayable and exitable | Conformant | Contract + world-model + ledger are plain and portable; `reactor-devtools <state-dir>` replays a saved run with zero running reactor and zero key |
|
|
|
|
### Honest current limits for authors
|
|
|
|
- **`### Continuity` self-driven recheck is wired, but the cadence is flat.**
|
|
The continuity scheduler drives the freshness-lapse → synthetic self-receipt
|
|
bridge (a lapsed `valid_until` flips a fact's status, moves the facet
|
|
fingerprint, and wakes the node — a **zero-token** fingerprint move, not a
|
|
model re-render). `reactor serve` polls it on a flat `--poll-interval`
|
|
(default 60s); **forecast-paced / adaptive idle** off each node's soonest
|
|
`next_self_recheck` is deferred. Declare `valid_until` now; the cadence
|
|
tightens later without a source change.
|
|
- **Serve ingress is local cron-poll + HTTP only.** Gateway poll connectors and
|
|
an HTTP trigger surface ship; **queues, file watches, and provider
|
|
subscriptions** do not. A worktree/planning-dir watcher must use a poll
|
|
`### Continuity` today and note the intended file-watch form.
|
|
- **The cryptographic signer is a null-state.** Composition pins a revision and
|
|
is chain-verifiable at the meaning layer, but pinning an *acceptable signer
|
|
set* for cross-trust-domain composition is not enforceable until the
|
|
byte-hash signer lands. Functionally adequate within one trust domain;
|
|
cryptographically weaker than the ideal across domains.
|
|
- **Materiality is authored, not yet inferred.** The author writes the
|
|
material/immaterial split in `### Maintains` prose and the compile session
|
|
lowers it. The skill does **not** infer facets or materiality from the truth's
|
|
shape; that inference loop is deferred. The store also does not materialize a
|
|
per-facet `published/<facet>/…` subtree on disk (it persists `published.json`
|
|
+ content-addressed blobs) — facet-granular propagation holds regardless; only
|
|
the on-disk subtree mirror is absent.
|
|
|
|
> The pattern is fully writable today, in the current model. Its remaining
|
|
> climb is harness cadence and cryptographic hardening (forecast-paced rechecks,
|
|
> richer ingress adapters, the byte-hash signer), not retired vision. Author to
|
|
> the ideal; do not claim the runtime delivers the deferred items it does not.
|
|
|
|
---
|
|
|
|
## III. What Must Change In The Skill
|
|
|
|
The retired-model framings are gone: the skill already routes the current kinds
|
|
and sections, the examples are migrated, and `concepts/{responsibility,reactor}.md`
|
|
teach the no-judge model. What remains is the climb from "fully authorable in the
|
|
current model" to "every Part I payoff is also *delivered*" — a mix of finishing
|
|
the authoring story for the newest sections and the genuine harness deferrals.
|
|
|
|
### 1. Finish the facet authoring story
|
|
|
|
Facet propagation is live and the named-parts model is canonical, but two seams
|
|
are open:
|
|
|
|
- **Facet inference is deferred.** Today the author writes the `####` parts and
|
|
the material/immaterial split by hand. The skill should eventually offer a
|
|
lint that flags an under-faceted `### Maintains` (one giant atomic truth whose
|
|
consumers clearly want selectors) — and, post-v1, an inference pass that
|
|
proposes facets from the truth's shape.
|
|
- **The on-disk subtree mirror is absent.** The store fingerprints each facet's
|
|
material field-paths and persists `published.json` + content-addressed blobs;
|
|
it does not materialize a `published/<facet>/…` subtree. Author doctrine
|
|
should not promise a subtree on disk — describe facets as the *subscription
|
|
and fingerprint* unit, which is what actually ships.
|
|
|
|
### 2. Complete the no-judge postcondition doctrine in `contract-markdown.md`
|
|
|
|
`### Maintains` now carries four jobs (type, canonicalization, facets,
|
|
postconditions) and `### Continuity` is a structural wake-source declaration.
|
|
These are documented in `concepts/responsibility.md`; `contract-markdown.md`
|
|
should mirror the load they bear:
|
|
|
|
- `### Continuity` is the author's input to memoization and cadence — name the
|
|
freshness referents (`valid_until`) and the wake sources (input / self /
|
|
external), and make "nothing changed" cheaply observable.
|
|
- Postconditions are the author's commit gate. State them as observable
|
|
referents; when the truth has *nothing observable to maintain against*, that
|
|
is an expected, high-value `failed` receipt routed to the author — **never** a
|
|
`blocked`/`drifting` status enum (those are retired).
|
|
|
|
### 3. Land the materiality lowering's prose→spec half
|
|
|
|
Compile runs as SKILL-loaded sessions and the **spec→code** canonicalizer
|
|
lowering is real (a compile session emits the canonicalization spec; the
|
|
deterministic producer compiles it). The remaining work is hardening the
|
|
**prose→spec** step — reading the author's `### Maintains` materiality prose into
|
|
the spec reliably — so that "state the materiality, not the hash" is trustworthy
|
|
across more contract shapes. This is a compile-session quality effort, not a new
|
|
grammar; there is no `.prose` parser to build.
|
|
|
|
### 4. Forecast-paced continuity cadence
|
|
|
|
The self-driven recheck path is wired (freshness-lapse → synthetic self-receipt,
|
|
a zero-token fingerprint move), but `reactor serve` polls it on a flat
|
|
`--poll-interval`. The deferred work is arming each node's soonest
|
|
`next_self_recheck` off its freshness so an idle reactor sleeps to the next real
|
|
expiry instead of waking every interval — the *forecast-paced quiescence* Part I
|
|
implies. The author already writes the `valid_until` that feeds it; the cadence
|
|
tightens harness-side, without a source change.
|
|
|
|
### 5. Richer serve ingress adapters
|
|
|
|
`reactor serve` supports local cron-poll and HTTP, plus gateway poll connectors
|
|
with a durable idempotency cursor. Queues, file watches, provider subscriptions,
|
|
and webhook authentication remain later runtime phases. Until they land, a
|
|
file-watch-shaped responsibility is authored as a poll `### Continuity`; the
|
|
intended ingress form should be noted in the contract so it migrates cleanly.
|
|
|
|
### 6. The cryptographic signer (cross-trust-domain composition)
|
|
|
|
The receipt ledger is content-addressed and chain-verifiable, and the `signer`
|
|
is an explicit null-state (`kind: "null" | "signed"`, only `null` shipped). v1
|
|
"signed" means meaning-layer chain-consistency. The deferred milestone is the
|
|
cryptographic byte-hash signer, after which a downstream can pin an *acceptable
|
|
signer set* in `### Requires` and have it enforced — closing the cross-trust-domain
|
|
supply-chain edge that is, today, the author's discipline rather than the
|
|
runtime's guarantee.
|
|
|
|
### Definition of done for the authoring layer
|
|
|
|
- `contract-markdown.md` documents `### Continuity` as the cadence/memo input
|
|
and `### Maintains` postconditions as the commit gate, with the
|
|
retired-status-enum doctrine explicit.
|
|
- A facet under-faceting lint exists; doctrine never promises an on-disk
|
|
`published/<facet>/…` subtree.
|
|
- The prose→spec materiality lowering is hardened across the example corpus.
|
|
- `reactor serve` arms `next_self_recheck` (forecast-paced cadence) so an idle
|
|
reactor sleeps to the next real expiry.
|
|
- The cryptographic signer lands and a pinned signer set is enforceable for
|
|
cross-trust-domain composition.
|
|
|
|
### Open authoring items
|
|
|
|
Deferred by design, tracked so they are neither invented nor dropped:
|
|
|
|
1. **The fixpoint (topology-as-responsibility).** Mounting the compile-phase
|
|
renders — Forme above all — as ordinary nodes so the reconciler wakes them on
|
|
a contract-set-change receipt, and the system maintains itself, is the
|
|
closing recursion. It is **post-v1** by design; v1 runs compile as a batch
|
|
step on contract change with the topology a fixed input per scheduling epoch.
|
|
This is the deliberate deferral, not an oversight.
|
|
2. **Facet / materiality inference.** The author states facets and materiality
|
|
today; an inference loop that proposes them from the truth's shape is
|
|
v-next.
|
|
3. **Ledger compaction.** A signed-snapshot-plus-truncate path for high-churn
|
|
nodes is deferred; today the ledger is the full append-only trail.
|
|
4. **The default `valid_until` freshness projector for serve.** A first-class
|
|
serve-time projector that surfaces soonest-expiry across nodes (the input to
|
|
adaptive idle) rides with the forecast-paced cadence work above.
|
|
|
|
> `02-ReactorHarness.md` says what the machine must do.
|
|
> `03-ReactorPattern.md` says what to write so it does it. The pattern is
|
|
> fully writable now in the current model; its full power lands as the harness
|
|
> climbs from flat-poll continuity and a null-state signer to forecast-paced
|
|
> rechecks and a cryptographic chain — and, last, to the fixpoint. Author to the
|
|
> ideal, document the climb honestly.
|