* feat: make contract id: optional and hold every declared id to its format
The format doc required id: on every responsibility and the compiler CLI
preflighted for it, yet nothing downstream read the field: the IR keys
nodes by slug, the state backends key the world model by node, and the
fingerprint is over content. Sixty-seven of 86 example responsibilities
had no id and half of the ids that existed were hand-typed slugs, so 12
of 29 examples refused to compile for a rule with no consumer.
id: is now optional on responsibilities and gateways: the slug is the
identity by default, and a declared id is the source identity that
survives renames. The format doc, compiler instruction, CLI preflight,
changelog conventions, and language spec all say the same thing. The
eleven hand-typed slug ids in the corpus are dropped, since they named
nothing the slug does not, and the two over-long compiler fixture ids
are trimmed to the documented 26-character Crockford shape.
scripts/mint-contract-id.mjs mints ids for authors who want one and
repairs malformed ids in place. A new corpus suite walks every example
and holds each declared id to the format, checks uniqueness, and keeps
version: in semver form.
* fix: fold every example section into the canonical set
Twenty-two headings across 18 example contracts were near-misses of a
canonical section, so the VM lowered them to plain documentation instead
of the semantics their authors meant. Continuity headings that carried
the driven-ness in the title become a bare Continuity section with the
driven-ness as its first bullet. Postconditions bullets fold into
Maintains. Facets become named parts under Maintains, each with a
material boundary. Failure containment becomes Invariants, a Continuity
recheck becomes the self-driven bullet, and a gateway's watched globs
move into Receives.
A new corpus suite walks every example and holds each ### heading to
the canonical table in the format doc, cross-checking its own list
against the table so the two cannot drift apart. The three inbound-
email examples join the intelligent-react shape suite, and the four
implementation-pipeline contracts join the facet-named-parts suite, so
no example is invisible to CI.
* fix: every example Requires now names a producer in its own set
Three examples carried needs that Forme could never satisfy from their
own contracts. competitor-activity named three signal feeds that existed
only in parentheticals; research-inbox-triage named a question list and
an owner roster nothing produced; agent-observatory named four adapter
mount instances that lived only in its README.
The format doc gains a short rule for facet families and per-entity
mounts: a placeholder facet heading declares a family, a placeholder
need subscribes to one member, and the harness binds the member at
mount time while the compiler emits the family. Forme's matching step
says the same.
competitor-activity gains a signal-feeds gateway with one facet per
signal, so the monitor's three needs resolve facet by facet.
research-inbox-triage gains a research-registry gateway that brings the
human-maintained questions and roster into the graph. agent-observatory
rewrites its adapter needs in family form and stays at nine contracts.
Each example reaches Forme with zero unsatisfied needs and an acyclic
topology. The new contracts join the facet-named-parts suite, and
competitor-activity joins the intelligent-react shape suite.
* docs: attribute described example topologies to the reference harness
Eight example READMEs state node and edge counts that mounting src/
alone cannot produce; the numbers come from the reference harness's
per-entity expansion. Each README now says so in the sentence that
carries the count and points at the repository README's Harnesses
section, and no Conformance expectations section states a count that
src/ cannot mount. The corpus index says the same for the set.
A new corpus suite walks every example README, counts the contracts
src/ mounts, and requires any larger claim to share its sentence with
the attribution, so a future README cannot over-claim silently.
* docs: specify node identity, artifact locators, and the receipt cost shape
The IR doc keyed every worked example by slug without saying what the
node key is. It now states the two-identifier model: node is mount
identity, unique within a manifest and defaulting to the slug for a
single mount, while a declared frontmatter id: is the source identity
behind it and is not emitted in a version 2 manifest. The same doc says
what an artifact locator resolves against: the OpenProse root, for
canonicalizers and postconditions alike.
The reconciler concept doc gives the receipt cost field its sub-shape,
including the surprise_cause that must equal the wake source, which is
what makes cost-scales-with-surprise observable. Doc-conformance
assertions pin each addition in the suite that already owns the file.
No IR schema bump; the expected and invalid fixtures validate unchanged.
* docs: cite in-repo sections instead of private design documents
Thirty shipped files, from the format doc and the state backends to the
example contracts and the conformance tests, cited design documents by
section that live outside this repository. A public clone should never
point its readers at text they cannot open.
Every citation now names the in-repo section that owns the rule, such
as the named-parts rule in the format doc or the fingerprint rules in
the reconciler concept, or the sentence simply stands on its own where
it needed no support. Test titles that carried a citation are retitled.
No links were added; the replacements are prose a stranger can follow.
* docs: pin harness status facts and guard the spec against rot
The spec marked implementation-status facts with the word "today" and
no attribution, so they would rot silently now that the reference
harness versions on its own. Six claims about poll cadence, the unwired
commit gate, the thin v0 receipt, the flat serve loop, and the dropped
Schedule section now name the reference harness and the version they
describe, and point once per document at the repository README's
Harnesses section. The two spec documents agree on a harness-chosen
receipt ledger layout. Two ideation links and a stray phase marker are
gone, the README's Harnesses link targets the harness spec, and its
version sentence defers to SKILL.md as the version of record.
The version script writes each manifest field on its own line instead
of round-tripping the file through jq, so a bump no longer reflows the
codex manifest; that manifest's capabilities array is collapsed back to
one line. Three guards land in the suites that own the territory: no
shipped file may cite a private design document, every relative link
in spec/ and skills/ must resolve, and the README may not hardcode a
skill version.
* chore: release skill 0.18.0
The format doc gained documented surface this cycle: id: is optional
with the slug as default identity, version: is author-owned provenance,
and facet families and per-entity mounts have a notation. The example
corpus is compiler-clean under those rules and the keyless conformance
suite proves it. That is a minor bump on the skill track.
The changelog entry tells an author what changed in authored files and
that a missing id: is no longer a compile error. runtime_contract stays
at 2, so prose upgrade needs no source rewrite. The version script now
touches exactly one line per manifest, which this bump demonstrates.
The gate is about to become a required status check on main. A required
check that is path-filtered never reports on a pull request outside the
filter, and that pull request then waits forever on a check that will
never arrive. The suites read Markdown off disk with no build step, no
model key, and no network, so running them unconditionally costs well
under a minute.
With the Reactor harness in its own repository, the language describes
its run-phase model for what it is rather than after one implementation
of it.
- concepts/reactor.md → concepts/reconciler.md; spec/02 keeps only the
contract any conforming harness must satisfy (02-Harness.md) and
spec/03 becomes 03-AuthoringPattern.md. "Reactor" in the model sense
is now "the reconciler" across the Skill, std, and the examples.
- The example corpus is harness-neutral: authored intent plus the
observable behaviour a harness must preserve. Quick Start examples
carry the Skill's own flow (prose compile → promote → prose serve)
and say what serve waits for; expanded-topology examples state what
src/ ships and what a harness's expansion produces from it.
- The Skill's run-flow docs agree with each other and with the spec:
serve defines the manifest promotion step, compile names what
ir-v0.md emits, ir-v0.md is the authoritative IR contract, and the
spec lists compile/serve/status as in-session verbs that a conforming
harness may deliver durably outside the session.
- A harness-surface conformance test keeps product tokens out of the
Skill, spec, std/co, and root docs, outside the README's Harnesses
section and the Skill changelog.
Skill 0.16.0; runtime_contract stays 2. The Skill changelog records the
migration so prose upgrade can route workflows that used prose react.
Reactor now lives at github.com/openprose/reactor with its complete
history and a pinned copy of the Skill at skill-v0.15.0; its packages
(@openprose/reactor 0.3.3, reactor-cli 0.2.4, reactor-devtools 0.3.1)
publish from there and are labelled experimental (alpha).
This repository is OpenProse only again: the language spec, the Skill,
std/co, and the examples — installable and testable with no build step.
- Remove packages/reactor*, tools/eval-harness, the Reactor-driven
example suites and test kits, both Reactor workflows, and the vitest
aliases into packages/reactor/dist.
- Retire `prose react`, the reactor shell-out exception, and reactor.md
from the Skill; replace the README's Reactor section with a short
"Harnesses" pointer.
- Keep the four corpus-wide example guards as tests/open-prose/examples-corpus.
- Add ci-skill.yml: pnpm install --frozen-lockfile && pnpm test:skill —
the conformance suites now run in CI for the first time.
- Record the `prose react` and reactor-cli changelog entries under the
tags they actually shipped in.
The run-phase vocabulary (concepts/reactor.md, the spec titles) is
de-branded in a follow-up.
Cut the reactor train so the #136 canonicalizer fix (#153) reaches npm, along
with the reactor.yml provider/temperature fixes (#137, #138), the key-material
scrub, the MK-1 height-ordered drain, and the re-skinned replay viewer.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dependency installs and CI jobs both executed code this repo never
reviewed. This closes those paths without changing what anything
resolves to.
pnpm 9 ran every dependency's install lifecycle script and had no
allow-list model, so CI executed install hooks from the whole tree on
every PR. pnpm 10.34.5 blocks them by default and carries the fix for
the fail-open integrity check in CVE-2026-50021. minimumReleaseAge holds
freshly published versions out of resolution for 48 hours, the window in
which a registry compromise is typically caught and yanked.
The two `*` peer ranges in reactor-cli were the only place the workspace
opted out of range discipline: any future major satisfied them, including
a hijacked one. Both now carry carets on the versions already resolved,
and the README install lines are pinned to match, since a 0.x caret does
not cross the minor line.
Third-party actions take the commit SHA their movable tags resolved to,
with a monthly grouped Dependabot entry so those pins do not go stale.
GitHub-maintained actions stay on tags as a stated trust decision rather
than a claim that pinning them would buy nothing.
The benchmark jobs needed the most work, since they run an external
repository's code with five LLM provider keys in scope. Dispatch inputs
now travel through the step environment as quoted variables instead of
being interpolated into shell. The pi version is hardcoded rather than
dispatchable: npm accepts package sources after the `@` — an alias, a
repository, a tarball URL — so an input in that position chose a package
rather than a version. The remaining ref override is documented as an
operator escape hatch whose clone target is fixed.
The publish job holds a credential that can publish under our name and
installed npm at latest before using it. It now pins an exact version
above the floor OIDC trusted publishing requires, and fails at that step
if the pin does not take.
CI also fails on a tampered or unsigned tarball now, checked per
publishable package rather than once at the root where npm would only
see dev tooling. The advisory audit runs alongside it as a signal, not a
gate.
Nothing re-resolves: no version or integrity line in the lockfile moves.
The skill-meta suite was coupled to exact onboarding copy, so harmless
wording changes could fail CI even when the documented contract remained
correct.
Replace the slogan assertion with behavior-oriented checks for the
example's Requires and Maintains contracts, absence of execution
choreography, and retired kind: system. Scope Markdown extraction to the
intended sections and add negative regressions so misplaced fences or
near-match headings cannot satisfy the test.
Rendered artifacts can contain both an `@atomic.json` status file and a real
structured backing such as `sources.json`. The lexicographic fallback selected
the reserved status file first, reducing declared facets to `null` and
preventing downstream propagation.
Exclude `@`-prefixed JSON basenames from structured-backing candidates while
preserving the `state/` preference and deterministic fallback ordering. Add
regression coverage for root and nested reserved files, reserved-only
artifacts, and the existing `state/` behavior.
Fixes#136.
The smoke fixtures still exercised the retired pre-0.15 model: service
and system kinds, '### Ensures' contracts, and a harness that asked for
forme.manifest.json and checked every output under bindings/. The
execution docs now treat retired kinds as never-executable upgrade
input, which turned the kind-test case into a standing contradiction:
its subject resolved to a kind: service file the harness required to
execute. That contradiction fits kind-test's history as the suite's one
chronically flaky case.
Rewrite every fixture in current kinds while preserving what each case
smokes: functions for single render, caller input, execution block,
errors and strategies, and local pattern instantiation (standalone runs
publish '### Returns' under bindings/ via copy-on-return);
responsibility multi-node files for the wiring cases, with a deliberate
fan-in reconvergence replacing the retired '### Wiring' case; kind: test
now runs a function subject and asserts against its published bindings.
Align the harness with the current artifact layout: mounted runs
snapshot compiled-intent.json, publish node truth under world-model/,
and append receipts; a per-case outputRoot field selects world-model or
bindings for output checks. Give the test command a 40-turn budget,
since it reads the test file, resolves the subject, executes it, and
evaluates assertions in one session. Case ids and filenames are
unchanged, so required check names stay stable.
The skill's execution reference taught two models at once. Its head
sections describe the current runtime: responsibility and function
kinds, the deterministic reconciler, renders that self-police their
postconditions, world-model publishing with receipts. Its body still
taught the retired one: ### Ensures contracts, a post-render judgment
call on outputs, and the workspace-to-bindings copy as the publish
step.
Migrate the body to match the head and align the depicted run envelope
with the filesystem backend spec: compiled-intent.json, caller inputs
at world-model/caller/, a receipts/ ledger, rendered and skipped log
markers, and resumption from the receipt chain. ### Execution blocks
are intra-node choreography, the render body of the one node that
declares them. Copy-on-return survives only for standalone function
runs.
Retired kinds now refuse to execute: a file declaring kind: service or
kind: system halts and routes to prose upgrade instead of running under
either semantics. Compatibility is migration at the source, never
interpretation at runtime.
The backend spec gets the same pass so the pair reads as one wire
format: its marker tables, log example, header comments, and
write-trigger table move to node, render, and run vocabulary.
agent-onboarding.md is served verbatim as raw text (the prose.md
arrival narrative and the agents.openprose.ai text site), so its first
bytes are the product. An agent fetching it read 25 lines of HTML
comment about routing and editing before the first heading, and parts
of that comment had gone stale.
Drop the comment so the file starts at the title, align the host list
with SKILL.md (Claude Code, Codex CLI, OpenCode, Amp), say multi-node
contracts in the capability note to match the current contract
vocabulary, and tidy punctuation. The narrative itself is unchanged.
The CLI and devtools readmes pointed at notes that are not in the
repository. Drop the dangling pointers so every reference on the public
surface resolves.
The tenets still steered contributors toward retired constructs:
judges, kind service wiring, and an Ensures/Shape/Strategies section
list. Reword them around responsibilities, facets, and the
Requires-to-Maintains match Forme actually performs.
The front page of openprose/prose read mostly as a Reactor README: the
tagline, quickstart, SDK tour, and examples were all harness. Reorder it
so OpenProse the language leads, add the missing skill quickstart
(npx skills add openprose/prose), and consolidate everything Reactor
into one self-contained section with its own tagline. Also state the
failure semantics precisely (a failed render leaves prior truth
standing) and swap remaining em dashes for house punctuation.
A light refresh of the README header and the project tagline.
- New README banner image (`assets/readme-header.png`); trims the caption now that the banner carries it.
- Brings the tagline in line across the README, plugin manifests, spec, and onboarding: "Stop scripting agents. Declare them."
- Removes the unused legacy `readme-header.svg` (nothing references it).
- Small `assets/README.md` tidy.
No functional changes.
`reactor trigger` never threaded the configured provider into the render: it
called the run-project with no provider, model, or decoding settings, so a live
trigger always fell back to the SDK's default OpenRouter provider and model
regardless of reactor.yml. With only the configured provider's key present,
every trigger produced a bare, causeless `failed` receipt (model "none", zero
tokens). Separately, the reason a render failed was computed but never
persisted, so every surface could only say `failed` with no way to learn the
cause without editing the source.
This fixes both:
- `trigger` resolves the provider plan, fails fast with an actionable error
naming the exact env var when a custom provider's key is missing, and threads
render_model, temperature, and reasoning_effort plus the provider into the
render exactly like `run` and `serve`.
- A failed render now records its reason on the receipt, inside the
semantic_diff (no new receipt field and no schema change, so existing
.reactor/ ledgers keep verifying), and `run`, `trigger`, `logs`, `trace`, and
`inspect` all show it. Secret material in a reason is scrubbed before it is
stored or printed.
- `serve` reports per-gateway poll activity each cycle, so a poll that stages
nothing is no longer indistinguishable from a healthy one.
Behavior changes: `trigger` now exits non-zero on a failed render or a missing
provider key (it previously returned 0), and a project configured for a
non-default provider with only OPENROUTER_API_KEY present now errors asking for
the configured key instead of silently rendering through the wrong provider.
OpenAI reasoning models (gpt-5.5, the o-series) reject any explicit
temperature unless reasoning_effort is none, but the reactor always sent
one: the config hard-defaulted a missing temperature to 0, the render and
compile harnesses coerced unset to 0, and mergeModelSettings always
attached the key. Deleting the temperature line from reactor.yml changed
nothing, so no configuration made these models compile or render.
Separately, a configured temperature only ever reached compile sessions —
run and serve renders silently used the SDK default, so reactor.yml's
temperature was honored at compile but ignored at render.
Temperature is now optional end to end. An absent reactor.yml line (or an
unset SDK RenderOptions/CompileSessionConfig temperature) sends no
temperature and the provider's default applies; an explicit value,
including 0 for greedy decoding, is sent verbatim. run, serve, and the
multi-reactor host thread the configured temperature into renders exactly
like render_model, so one reactor.yml value governs both compile and
render.
A new optional reasoning_effort key (model.reasoning_effort in reactor.yml,
reasoningEffort in the SDK render/compile options) passes through verbatim
into modelSettings.reasoning.effort, so a reasoning model can keep a custom
temperature by pairing it with reasoning_effort: none. doctor --live no
longer pins temperature 0 in its probe (it 400ed against reasoning render
models), and a provider temperature-rejection 400 now maps to an actionable
hint naming the reactor.yml line to delete.
Behavior change: a project with no temperature line previously sent an
implicit 0; it now sends none and decoding follows the provider default.
Set temperature: 0 to keep greedy decoding — the reactor init scaffold
still writes it, so new projects are unaffected.
Adds focused unit coverage for a path that had none: temperature omitted
when unset and sent exactly when configured (render and compile request
capture), the config parse and run-path threading, and the scaffold pin.
Each runtime example shipped a committed replay/ state-dir that duplicated
fixtures @openprose/reactor-devtools already generates and publishes, and the
example generators forked the devtools generators. Now each recorded run and
its generator logic lives once.
- masked-relay, inbox-triage and research-tree import the canonical generators
from reactor-devtools and add only the example-library files (labels.json +
beats.json) on top, dropping the forked copies.
- Every example regenerates its replay/ into a tmpdir at test time and proves
determinism by two fresh generations agreeing; the committed bytes for the
six scenarios that mirror the devtools fixtures, plus tamper-forge, are
removed. The examples with no devtools counterpart keep their committed state.
- agent-observatory keeps its own generator on purpose: it teaches a different
story (four runtimes, a session-to-prose node, dual Markdown and HTML
artifacts) than the devtools corpus fixture, now noted in its header.
- Drop stale internal tracker references from the tamper-forge contract,
generator and tests.
Offline gate green: pnpm build && pnpm test:skill && pnpm test:examples.
prose.md is now the canonical product host; the apex/www openprose.ai and
docs.openprose.ai redirect to it. Update the self-referential links in agent
onboarding, the Codex plugin websiteURL, the asset docs, and the Reactor
technical report so they target prose.md / docs.prose.md directly instead of
bouncing through a redirect.
The height-ordered reconciler drain renders each recombinant (diamond) join
once, against fully-settled inputs, instead of the old arrival-order
double-render. The committed example replay/ trails and two assertions still
encoded the pre-drain receipt shape.
- Regenerate the committed replay/ for the six affected examples to the current
SDK output (masked-relay drops 77 -> 41 receipts; tamper-forge lenses the same
trail; agent-observatory, inbox-triage, basic-unit-suite, github-star-enricher
follow).
- github-star-enricher: a shared company diamond now coalesces into a single
render, so the second arm no longer mints a memo-skip receipt. Assert the reuse
via the single shared render (the stable signal) rather than a per-wake skip.
- tamper-forge: update the audited trail length (77 -> 41) in the test, the
generator beats, and the README/contract that cite it.
Offline gate green: build && test:skill && test:examples.
pnpm install --frozen-lockfile (used by CI, including the examples gate) fails
because the lockfile drifted from the workspace package.json files:
- reactor-cli pins @openprose/reactor as workspace:* in the lockfile but
workspace:^ in package.json.
- reactor-evals is a workspace package but was never recorded in the lockfile.
Regenerated with the pinned pnpm 9.15.0 via pnpm install --lockfile-only.
pnpm install --frozen-lockfile now passes.
Live render path validated end-to-end on OpenAI gpt-5.4-mini direct (real
metered receipt 36/4/40) after the OpenRouter key hit its limit. Per
decision, the shipped headline is the deterministic, price-independent
174.71x fresh-token fold; the full metered N=1 dollar bill is a bounded
follow-up, not fabricated. Updates live_n1, model_pin, and limitations note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The U12 poison guard used text.includes('256:0'), which false-matched the
'sha256:0…' content-hash prefix saturating every receipt ledger — so the
gate exited 1 on the committed runs-sample. Match poison tokens only when
they stand alone, so a reused FIGURE is still caught but a hash digest is not.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The '2026 H2' target was an unratified placeholder. Replace with 'tracked
but not yet scheduled (C3)' at the three disclosure sites so no public
artifact commits to a quarter that isn't on the roadmap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A live provider 403 ('Key limit exceeded') echoes the key's SHA-256 in an
openrouter.ai/.../keys/<hash> management URL — a key fingerprint that reached
test output / CI logs. Add redactSecrets/redactError (scrubs sk-* key
families, Bearer/Authorization headers, /keys/<hash>, and bare long-hex
fingerprints) and apply at the two render error chokepoints (render-backend
re-throw + smokeRun). 7 redaction unit tests with fully fabricated fixtures;
verified the real BYO live 403 now surfaces as .../keys/***REDACTED***.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New packages/reactor-evals/ — preregistered, equal-correctness-gated
offline benchmark minting the first measured 'cost scales with surprise'
result (~174x fewer fresh tokens than an equal-correctness cron at lambda=1%,
decaying to 1.36x at lambda=1.0). Deterministic ledger, 30/30 chain-verified
receipts, poison-grep + decidability guards. Authored against the public
SDK barrel; spec + reactor/src read-only. U10 live dollar-run is operator-
gated (follow-up).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace both arrival-order FIFO drains (drain/drainAsync) with a
compile-time height-ordered, dirty-input-count-gated drain so a staggered
unequal-path diamond renders its join once per settled wave (kills the
double-render glitch reproduced live in masked-relay). reconcile/
reconcileAsync + single-flight guard reused byte-for-byte; public API
unchanged; no spec edit. 11 new red-first regression tests (sync+async).
Closes#132.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mints the first preregistered, equal-correctness-gated measurement that Reactor's
fresh-token spend scales with surprise, not time. New packages/reactor-evals/
authored against the PUBLIC @openprose/reactor barrel (EVALS.md discipline);
spec/ and packages/reactor/src/** read-only.
Headline (deterministic offline ledger): at lambda=1%, Reactor spends ~174x fewer
fresh tokens than an equal-correctness cron; the fold DECAYS with the change-rate
(~1390x at lambda=0 -> 1.36x at lambda=1.0). Per-tick fresh regresses on the
PREREGISTERED material-change indicator (slope=30, intercept~0, permutation
p~1e-4); the null 'spend tracks wall-clock/event-count' is rejected for Reactor
and not for the cron. Every cost row gated to equal correctness vs the oracle.
Units: U1 deterministic-cost-v1 (preregistered surrogate); U2 lambda world-gen +
material projection + labels + oracle; U3 sweep (real reconciler, per-tick fresh
off the receipts); U4 six contestants (reactor/oracle-cron/content-cache/
no-memo/byte-diff/react-loop); U5 prereg hashed before any run; U6 scorers
(surprise-cost regression + permutation test, propagation #2, amortization #9,
gateCommit #6, per-node chain-verify); U7 equal-correctness gate + regime matrix;
U9 offline invariants #4/#5; U11 report + hero figure + suite CLI; U12 poison-grep
+ decidability guards. 30/30 cells chain-verified; 8/8 unit tests pass; prereg
hash + REPORT.md byte-stable across runs.
Deviations/blocked (honest): .cjs not .ts (toolchain availability; layout matches
the PLAN 1:1); U10 real N=1 LIVE run BLOCKED (no OPENROUTER_API_KEY) and never
fabricated; U8 long-horizon + U9 #8/#12 scaffolded; baseline coincidences flagged
in REPORT.md. Full runs/ (87M) gitignored (byte-deterministic, regenerable);
runs-sample/ commits the headline pair as a frozen chain-verifiable replay.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The arrival-order FIFO drains rendered a recombinant (diamond) join with
UNEQUAL path lengths TWICE: once prematurely against a half-propagated input
set (a glitch — the short edge moved, the long path still stale), then again
once the long path settled (a redundant render). "Cost scales with surprise"
(Invariant 5) visibly failed for that topology — reproducible live in the
shipped masked-relay demo.
Replace both `drain` and `drainAsync` with a compile-time height-ordered,
dirty-input-count-gated drain (Minsky / self-adjusting computation): a node
fires exactly once, in ascending height, only after every dirty producer has
SETTLED — so a join renders once, against fully-settled inputs.
- `computeHeights` + producer/subscriber adjacency, derived once per epoch from
the frozen topology edges ∪ entry_points (NOT topology.nodes, which is [] in
the IR). Cycle-guard throw kept; static-topology marker left for the fixpoint.
- One shared `startFrontier` core (PASS-1 dirty closure + dirty-count, the
height-ordered ready pick, settle-based decrement, move-aware prune) drives
both the sync and async loops; only the render call differs. `reconcile` /
`reconcileAsync` — including the per-node single-flight/coalesce guard — are
reused byte-for-byte. Async awaits each fire fully before advancing the
frontier (closes the await-frontier gap); stays serial (no Change-B parallelism).
- Settle-based (not move-based) decrement so a memo-skipping producer never
starves a join; move-aware prune so a no-change re-drain renders zero and
mints only the seed's skip; interior-seed gate so a directly-woken interior
node still waits on its dirty upstreams.
Public API unchanged; no caller edits (drain returns fire-order, not FIFO —
audited: no consumer asserts arrival order). No spec edit.
Tests (red-first; the primary demonstrably failed on the pre-fix FIFO drain,
E=2 with a glitch, proven in a scratch build): staggered unequal-path diamond
(sync + async) → join renders once against settled inputs; symmetric equal-path
control; no-change re-drain → zero renders / one seed skip; two-seeds-on-one-
chain interior-seed gate; 3-deep prune-no-deadlock; computeHeights height
assertions + forged-cyclic-topology throw. Full @openprose/reactor suite green.
Refs: planning/plans/2026-06-07-mk1-drain-fix/PLAN.md; backlog MK-1;
prototype planning/ideation/minsky-experiments/c2-topo-drain/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align the public artifacts with what npm and the code actually deliver — the
seams the 2026-06-06 investor-DD fanout independently verified as overstated.
Presentation/disclosure only; no runtime, invariant, or spec edit.
- IDD-vers: fix the two stale "live on npm" version callouts to reactor 0.3.1 /
CLI 0.2.2 (devtools 0.2.0 unchanged); reactor README "ideal surface" 0.3.0->0.3.1.
- IDD-reuse (+G27): devtools --describe COST ROLLUP now leads with the defensible
memo-skip count and demotes provider-prompt-cache `reuse=%` to a labeled
secondary line ("provider-reported; can be 0% on the default model"); test added.
- BR-F7 (+G10): dated cryptographic-signer roadmap line (targeted 2026 H2, tracked
as C3) at the three null-signer disclosure sites + the tamper-evident-not-proof
threat-model sentence. Also fixed the broken `@openprose/reactor/sdk` subpath
cites in the devtools README -> root `@openprose/reactor` (NOT `/internals` as
the plan said; these symbols are root exports), and the non-public
`new FileSystemReceiptLedger` -> the public `createFileSystemReceiptLedger`.
- IDD-footprint: rewrote the "Air-gapped?" note + added a quickstart footprint
line with the measured ~99 MB / ~100 packages (2026-06-06), preserving the
true SDK-core zero-dep claim.
- IDD-skew: ranged the devtools/CLI `@openprose/reactor` workspace ref
workspace:* -> workspace:^ (pnpm pack now emits ^0.3.1, verified) so npm
dedupes one SDK copy. (Republish of devtools 0.2.1 still required to land it on
npm — separate release action.)
Gate: pnpm --filter @openprose/reactor-devtools test green (96/96).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the prose-CLI scrub the spec already documents as shipped: deletes tools/cli (the @openprose/prose-cli Oclif binary + eval harnesses), drops tools/cli from the workspace and lockfile, and removes the separately-authored `### Criteria` section from the reactor and reactor-cli contract loaders (postconditions live solely in `### Maintains`). Updates the accompanying skill tests, changelog, and release docs. Verified green: reactor SDK 458/0/10, reactor-cli 186/1 (pre-existing doctor test), devtools 96/0, skill 413/0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Repairs surfaced by an independent code-grounded verification pass. 00: cost is observed-not-budgeted (not 'resource budget the gates are constrained by'); Tenet 2's intelligence layer lists all three model-authored compile artifacts (Forme topology + canonicalizer + postcondition validators). 01: state the `### Invariants` actuation-boundary ideal in Part I (with a bridge note it is authored-only today); gateway compiles to a trigger the reactor serves (not `prose serve`); migration line corrected (`co` has no `kind: responsibility`; std has 3); note the language-root `receipts.jsonl` vs the harness `receipts.json`. 02: launch DoD no longer implies version-equality; new Part III §10 (declared-capability resolution + serve auth + async storage seam) so every Honest-Limit has a forward item. 03: signer rendered as shipped (`scheme: "none"`, no `kind:"null"|"signed"`); Part II honest that `### Tools`/`### Environment`/`### Skills` are name-only and not harness-consumed; `as_of` added to the gap-cluster-2 receipt set; gateway `### Schedule` forward item; no `reactor test` subcommand.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconcile the OpenProse spec so Part I states the implementation-agnostic ideal, Part II matches shipped code, and Part III is a real actual->ideal path. Memo key stated as the 3-tuple (shipped 2-tuple as a bridge note); ideal receipt schema gains as_of + failure reason + author-addressing; precedence-stack scope and commit-gate pillar reconciled across 00/02/03; prose-CLI and `### Criteria` residue removed from the ideal; Part III re-baselined off shipped reality (the corpus migration retired as done) with the receipt-shape and actuation gap-cluster items added so every Part II limit has a forward item.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Capture the agent-observatory Reactor learnings as authoring doctrine,
scoped to multi-node Reactor pipelines so they are not over-applied.
guidance/authoring.md gains a `## Cost and Context Discipline` section
(tier with a cheap gatekeeper; bound each narrow render to its inline
input; validate the cost-shape; keep renders cheap-model-small) plus
four matching anti-patterns. SKILL.md's Authoring Guidance points to it
for continuous / fan-out / high-event-volume pipelines.
Opens with an explicit trigger and a Tenet-2 caveat: it applies to the
narrow-transform renders that dominate a pipeline's volume, not to
one-shot functions or single responsibilities, and a render whose job is
to explore should still explore. CLI/version gotchas are deliberately
left to reactor.md, not authoring doctrine.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The "Inbound email as a trigger" group was authored before the README index was
restyled to use a colon (not an em-dash) between each example link and its
description. Align the three bullets (support-inbox-router, feedback-pulse,
press-desk) to that convention. Cosmetic only.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(examples): inbound primitive.dev email as a Reactor trigger (3 examples)
Wire a primitive.dev email inbox in as an external-driven gateway and keep a
downstream world-model current from what arrives. Three distinct reactor shapes,
each shipping the full validity contract (committed replay/ + deterministic
tier-2 offline test) plus a key-gated tier-3 LLM-as-judge live test.
- support-inbox-router (marquee): a cheap-model spam/content filter + a faceted
router whose facets are channels. A per-email triage drops spam (its `routed`
facet stays the fixed NULL token, so junk lights nothing) and tags ham to a
channel; the router catalogues one facet per channel (bug-reports,
feature-requests, docs-questions, billing) so a docs question wakes ONLY the
docs-gap tracker, never the bug board. `billing` has zero consumers on purpose
(a facet is a subscription symbol). The docs-gap tracker feeds the agent-native
docs / llms.txt surface.
- feedback-pulse: rollup aggregation + self-driven weekly `valid_until`
freshness; the brief refreshes on cadence even when the inbox is quiet, at zero
tokens on an unmoved rollup.
- press-desk: a deterministic human gate (gateCommit: needs_human,
auto_reply:false) + a privacy projection facet that keeps sender PII out of the
public view by construction.
Tier-2 offline: 45/45 new tests pass, byte-deterministic, chain-verifying; no
regression to the existing suite. Tier-3 live tests passing-skip offline and run
the render on a cheap model with a smart judge model when keyed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(examples): validate tier-3 LLM-judge live tests on direct OpenAI
OpenRouter is over its account spend cap, so point the three live tests at the
OpenAI Chat Completions surface directly with OPENAI_API_KEY: the render-under-
test runs on the cheap model (gpt-5.4-mini) and the rubric judge on a smarter one
(gpt-5.5), both via the same key. gating now resolves OPENAI_API_KEY (process.env
then the .env at REACTOR_ENV_PATH, honoring REACTOR_OFFLINE) and the body still
passing-skips offline. temperature pinned to 1 (the gpt-5.x models reject 0).
All three live tests pass live at reliability >= 0.8 across their labeled sets
(support-inbox-router spam/bug/feature/docs, feedback-pulse themes, press-desk
relevance/kind/no-PII-leak), grounding guard held. Offline gate unchanged: 45/45
tier-2 pass, live bodies passing-skip.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Frame OpenProse as a declarative language: you declare the ideal world
state, the Reactor keeps it true. Make that the spine across both layers
and present cost-scales-with-surprise as its consequence rather than the
headline. Sweep em dashes for a cleaner read.
The open-prose skill ships as a plain folder, so everything under
skills/open-prose/examples/ reaches every install. Each runtime example
shipped a committed replay/ state-dir (around 480 binary world-model files), a
generator, and a test suite wired to the workspace through a dist alias with no
local package.json. That machinery is internal validation, not the template a
user lifts: it cannot run from a copied folder, and it shipped generated
artifacts nobody should copy.
Keep the shipped examples to what a user actually adapts, and move the
validation into the repo's test tree:
- Move each example's tests, generator, and committed replay/ into
tests/open-prose/examples/<name>/. The shipped example is now its .prose
contracts under src/, a README, and a .gitignore.
- Re-point the vitest include and the test scripts; the byte-deterministic
offline coverage runs unchanged, just rooted under tests/.
- Rewrite the example READMEs to point at the reactor CLI for producing and
replaying a run, and drop the stale committed-fixture sections.
- Update the examples-gate workflow description to match the new layout.
No language, CLI, or runtime behavior changes, and the example contracts are
untouched. Verified with the offline gate (REACTOR_OFFLINE=1): the conformance
suite, the relocated example tests, and the eval harness all pass.
* fix(cli): typecheck repository-reactor-bridge test against branded Receipt fields
#106 hard-branded the reactor Receipt identity fields (node: NodeId,
contract_fingerprint / fingerprints: Fingerprint) and added this bridge test in
the same commit, constructing the Receipt fixture from raw strings — so the test
was born failing tsc. CLI Release Check only runs on tools/cli + release-script
paths and main has no required checks, so #106 merged with the typecheck red and
it stayed hidden (no cli-path change re-ran the check) until a release-infra PR
surfaced it.
Author the fixture with the same brand constructors the production bridge uses
(asNodeId / asFingerprint from @openprose/reactor/internals). The constructors are
identity-at-runtime brands, so behavior is unchanged: the affected test passes
10/10 and tsc is clean.
Note: this unmasks a SEPARATE pre-existing failure, also from #106 — the
repository-ir compiler fixtures were regenerated with kind
"openprose.compile-phase-ir" while validateRepositoryIr and its tests still expect
"openprose.repository-ir" (23 failing tests). That is a distinct IR-reconciliation
fix, tracked separately.
* fix(cli): restore repository-ir v0 validator tests with CLI-owned fixtures
#106 migrated the SKILL compiler's golden outputs (repo-root
tests/open-prose/compiler/) from repository-ir v0 to compile-phase-ir v2, but the
CLI's own compile path (compileRepositorySource -> validateRepositoryIr ->
repositoryIrToTopology) stayed v0. repository-ir.test.ts and
responsibility-status.test.ts borrowed those golden files across the package
boundary, so the v0 validator was being fed v2 inputs -> 21 failing tests.
Give the CLI's v0 validator tests their OWN v0 fixtures under
tools/cli/tests/prose/fixtures/repository-ir/ (recovered from f12dcda~1, the last
commit before the migration; the CLI compiler and validator are unchanged since,
so they still describe the current contract). The two compilers no longer share
fixtures: the SKILL compiler's compile-phase-ir fixtures are validated by
compiler-ir.test.ts; these repository-ir v0 fixtures are the CLI's. A README in the
fixtures dir documents the split and the migration path.
No validator or compiler change (not papering over) — the v0 validator is simply
fed correct v0 inputs. tools/cli suite: 573 -> 594 passing; the v0 validator suite
is 30/30. The 2 remaining failures (quickstart's dangling deleted-demo reference
and the agent-observatory example's missing id) are unrelated non-IR #106 fallout,
tracked separately.
* chore: deprecate prose-cli npm publish flow; park the eval suite
The `prose` CLI (@openprose/prose-cli) is deprecated in favor of the reactor
harness (@openprose/reactor + @openprose/reactor-cli) and the SKILL/plugin. This
removes its npm publish flow (it will be marked deprecated on npm manually) and
parks the eval harness out of the working tree.
Rip out the prose-cli publish flow:
- delete .github/workflows/{release,cli-release-check,cli-real-harness-smoke}.yml
and scripts/release-preflight.sh (the "OpenProse Release" publisher + its
preflight/checks).
- drop the `cli` track from .version-bump.json (only the skill/plugin track
releases here now) and the prose-cli sections from RELEASE.md.
- decouple the root build/test/lint scripts from @openprose/prose-cli.
Park the eval suite (it is rethought from scratch in the reactor backlog):
- remove the judge-era harness tools/cli/src/evals (45) + tools/cli/tests/evals
(18) and spec/04-Evals.md; they are copied verbatim into the planning
backlog-reactor for rehydration, and the methodology is synthesized there.
The harness was import-isolated (no code imported it); removal breaks nothing.
- fix the now-dangling spec/02 cross-reference to 04-Evals.md.
- remove the obsolete quickstart.test.ts (it read a #106-deleted demo test file).
The reactor packages, the new reactor-native tools/eval-harness, the skill
examples gate, and plugin-manifest are unaffected; prose-cli still typechecks.
Re-skin the keyless DevTools replay SPA onto the apps/run design system's
"Reactor monitor" machine surface (DESIGN.md §1/§4 name it as a sanctioned dark
machine surface): a flat charcoal ground, single-voice self-hosted JetBrains
Mono, gold as the one brand accent, 1px hairlines + small radii + one soft
shadow framing, three-dot window chrome, and always-labeled status.
- Machine palette (variable NAMES preserved so app.js + every selector keep
working; only values changed): --bg #1a1c22 flat (radial gradient removed,
per "no gradients"), machine-bar chrome bars, machine-fg/dim text, white-alpha
hairlines.
- Disposition + wake-cause hues mapped to the machine signal palette, kept
distinct AND labeled (never colour-only): render = machine-ok green,
active/lit path + per-facet edge-light + cost-fresh + external-wake =
machine-gold, memo-skip = machine-dim grey, fail = machine red (deepened for
AA on charcoal), self-tick = labeled violet.
- Self-host JetBrains Mono (400/500/700 woff2, latin subset, ~65KB) under
src/public/fonts so the machine surface is the real face, offline + keyless.
- Fix copy:public to recurse (fs.cpSync) so the new fonts/ subdir builds and
ships (the old non-recursive copy threw ENOTSUP on a subdir).
Scope: CSS + index.html + fonts only. No app.js logic changes; all class names
and animation hooks preserved, so replay/scrub/animation behaviour is identical.
Verified: pnpm build + typecheck pass and the built server serves /app.css and
/fonts/*.woff2 (200).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Astro `reports` app (formerly apps/reports in openprose/platform,
publishing to reports.openprose.ai) is gone, leaving only this stale
`docs/reactor/v0.1/` content and a README describing a dead publishing
pipeline. The canonical documentation now lives at the Next.js/Fumadocs
site https://docs.openprose.ai (repo openprose/docs), which carries the
reactor technical report and architecture docs.
Removes `docs/` entirely and repoints the README's technical-report link
to the live docs site.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>