Skip to content

feat: bring the example corpus to conformance and release skill 0.18.0 - #172

Open
josemontesdeoca wants to merge 8 commits into
mainfrom
corpus-compiler-conformance
Open

feat: bring the example corpus to conformance and release skill 0.18.0#172
josemontesdeoca wants to merge 8 commits into
mainfrom
corpus-compiler-conformance

Conversation

@josemontesdeoca

@josemontesdeoca josemontesdeoca commented Sep 3, 2026

Copy link
Copy Markdown
Member

Companion to openprose/reactor#8, which names the generators that produce the topology counts these READMEs now attribute.

Why the change

The example corpus had never been checked against the skill's own format rules and had drifted four ways — frontmatter identity the format demanded but nothing read, ### headings outside the canonical set, ### Requires entries with no producer in their own example, and READMEs claiming node counts that mounting src/ cannot produce — so this repairs all four and adds tree-walking tests that keep every future example honest.

Special things to note

  • id: frontmatter goes from required to optional, and the 11 hand-typed ids in the corpus are dropped rather than re-minted. Nothing in the skill ever read the field: the IR keys nodes by slug, the state backends key the world model by {node}, and fingerprints are computed over content. A first pass that backfilled the 67 missing ids produced an 84-file diff of opaque lines for a feature with no consumer, so the rule was inverted instead. Under the optional rule a slug id names nothing the slug does not; the two compiler-fixture ids are trimmed to the documented 26 characters. prose upgrade may drop an id that merely repeats the slug — it must never add one.
  • The eight over-claiming READMEs keep their counts. monorepo-ci still says 22 nodes / 48 edges; the sentence now says the reference harness's per-entity expansion produces them and that src/ mounts 4 on its own. described-topologies.test.ts counts each example's mountable contracts itself, so a future README cannot over-claim silently. A companion one-sentence change on the harness side names its per-example generators as the expansion path.
  • bump-version.sh no longer writes JSON through jq. Round-tripping re-serialized the whole manifest (it once re-expanded a one-line array to four lines), so writes are now a line-anchored sed guarded by an exactly-one-match check; reads and --check still go through jq. A same-version bump is now byte-for-byte a no-op.

Change outline

The identity rule changes first, in the four places that state it.

 contract-markdown.md — ## Frontmatter
-A `kind: responsibility` file also declares required `id:` frontmatter to name
-the stable Markdown identity … The slug is display; `id:` is identity.
+A `kind: responsibility` or `kind: gateway` file may declare `id:` frontmatter
+to give the contract an identity that survives filename and `name:` renames.
+Without one, the slug is the identity. … 26 characters of uppercase Crockford
+base32, minted once by `scripts/mint-contract-id.mjs` and never hand-typed.
+`version:` is optional, author-owned provenance in semver form.

 compiler/index.prose.md — responsibility_compiler
-  Use frontmatter `id:` as the responsibility identity backing the node. Never
-  derive identity from `name:`, filepath, title, or a slug.
+  The node key in the topology is mount identity, assigned at mount; a single
+  mount of a contract defaults it to the slug. Frontmatter `id:`, when declared,
+  is the source identity behind that node and survives renames.

 compiler/index.prose.md — CLI preflight
-preflights the compile target source files for responsibility `id:` and
-required `### Tools` sections
+preflights the compile target source files for well-formed `id:` frontmatter
+where present and required `### Tools` sections

 spec/01-Language.md
-A `kind: responsibility` file carries a required `id:` field … the durable
-identity used to key world-model and receipt-ledger state.
+A `kind: responsibility` or `kind: gateway` file may carry an `id:` field …
+state is keyed by the mounted node, which defaults to the slug.

The format also gains the grammar the corpus was already reaching for: one facet per entity, where the entities are not known until run time.

contract-markdown.md — ## Maintains
  Facets — the named-parts rule               (existing)
  Facet families and per-entity mounts        (new)

    #### user:<login>    under Maintains  →  one facet per entity; shape shared,
                                             entity named at run time
    session:<id>         in a Requires     →  subscribes to one member of a family
    # Title [instance]   in the H1         →  a harness mounts this contract once
                                             per entity

  The contract declares the family; a harness instantiates facets and mounts.
  The compiler emits the family, never an enumeration — src/ lists no instances.

forme.md — matching step
  a placeholder facet-need matches any member of the named family; the harness
  binds the member at mount time

With the rules settled, the corpus is brought to them. Two gateways are new because a ### Requires with no producer in its own set is a dangling need, and the external truth those needs describe — vendor feeds, a human-maintained roster — is exactly what a gateway brings in.

 skills/open-prose/examples/                              29 examples, 158 contracts
 ├── competitor-activity/src/
+│   ├── signal-feeds.prose.md                            + gateway maintaining the three
+│   │                                                      signal facets as three parts
 │   └── competitor-activity-monitor.prose.md             ~ its three needs now name them
 ├── research-inbox-triage/src/
+│   ├── research-registry.prose.md                       + gateway for the roster and the
+│   │                                                      active-question list
 │   └── research-inbox-responsibility.prose.md           ~ its needs now name the registry
 ├── agent-observatory/src/
 │   ├── runtime-adapter.prose.md                         ~ Maintains gains a runtime:<name>
 │   │                                                      family; Requires names the
 │   │                                                      watch's per-runtime facet
 │   └── session-ledger.prose.md                          ~ four adapter mount names become
 │                                                          one family need
 ├── {monorepo-ci,implementation-pipeline,oblique-weave,
 │    github-star-enricher,forme-fixpoint,surprise-cost,
 │    basic-unit-suite,agent-observatory}/src/*.prose.md  ~ 22 non-canonical headings folded
 ├── {forme-fixpoint,monorepo-ci}/src/*.prose.md          ~ 11 hand-typed slug ids dropped
 └── {monorepo-ci,inbox-triage,implementation-pipeline,
      research-tree,agent-observatory,support-inbox-router,
      press-desk,feedback-pulse}/README.md                ~ counts attributed; counts removed
                                                            from Conformance expectations

The 22 headings fold into forms the format doc and the existing suites already define, so none of them is a new concept.

Non-canonical heading Sites Folds into
### Continuity: external-driven 8 ### Continuity + an - external-driven bullet
### Continuity: input-driven 3 ### Continuity + an - input-driven bullet
### Postconditions 4 - postcondition: bullets inside ### Maintains
### Facets 4 #### named parts inside ### Maintains
### Watches 1 the globs move into the gateway's ### Receives
### Failure containment 1 ### Invariants
### Continuity recheck 1 the self-driven bullet of ### Continuity

Then the tests that make the corpus stay this way. All three new suites discover their targets by walking the tree rather than naming the examples they own, so a new example is covered the day it lands instead of when someone remembers to add it to a list.

 tests/open-prose/examples-corpus/
+├── contract-identity.test.ts       + every id: present is 26-char Crockford and unique;
+│                                     version: is semver. Presence is never asserted.
+├── canonical-sections.test.ts      + every ### heading in the corpus is one of the 26
+│                                     canonical names, and the hardcoded set is checked
+│                                     against the format doc's table so the two cannot drift
+├── described-topologies.test.ts    + a node count above what src/ mounts must share its
+│                                     sentence with an attribution; a Conformance
+│                                     expectations section states no node or edge count
 ├── intelligent-react-…test.ts      ~ now owns competitor-activity, feedback-pulse,
 │                                     press-desk, support-inbox-router
 └── facet-named-parts.test.ts       ~ covers the two new gateways
 tests/open-prose/
 ├── stale-docs/stale-docs.test.ts   ~ no shipped file cites a document that is not in the
 │                                     repo; every relative link in spec/ and skills/ resolves
 └── skill-meta/skill-meta.test.ts   ~ pins 0.18.0; the README may not hardcode a version

Each new suite was checked against a deliberately broken file — a non-canonical heading, a slug-shaped id:, and an unattributed count — and each named the offender rather than passing. pnpm test:skill is green: 19 files, 301 tests.

Finally, the docs close the gaps the corpus walk exposed and stop the status claims from rotting.

 compiler/ir-v0.md
+  ### Node identity      + `node` is mount identity: unique within a manifest, stable
+                           across recompiles of an unchanged set, and defaulting to the
+                           slug for a single mount. `contract_fingerprint` ties a node to
+                           its source; frontmatter `id:` is not emitted in a version 2
+                           manifest, so no schema bump and no fixture churn.
+  ### Artifact locators  + `artifact` is a path relative to the OpenProse root, resolved
+                           by the run phase; applies to postconditions too

 concepts/reconciler.md — the receipt table
-| `cost` | mechanical token attribution — makes "cost scales with surprise" observable |
+| `cost` | `{ provider, model, tokens: { fresh, reused }, surprise_cause }`; `surprise_cause`
+          names the wake source that caused the spend and must equal `wake.source` |

 spec/{01-Language,03-AuthoringPattern}.md
+  six implementation-status claims (poll cadence, gateCommit wiring, the thin v0 receipt,
+  the dropped `### Schedule`) now name the reference harness 0.3.3 they describe, so they
+  read as dated rather than wrong once that harness moves on; both chapters now agree that
+  the receipt ledger layout is the harness's choice

 scripts/mint-contract-id.mjs
+  dependency-free minting for authors who want a stable id: prints one, `--ensure` repairs
+  a malformed id in place, `--check` reports. It is not run against the corpus in this
+  release.

The skill ships as 0.18.0 with a changelog entry; runtime_contract stays at 2, so no authored file needs rewriting.

…rmat

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.
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.
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.
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.
…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.
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.
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.
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants