Skip to content

Declare the daemon's verbs in its contract directory, ship it in plugin-hostd-contract (#131) - #170

Merged
linuxnow merged 9 commits into
mainfrom
feat/131-verbs-contract
Oct 26, 2026
Merged

linuxnow merged 9 commits into
mainfrom
feat/131-verbs-contract

Conversation

@linuxnow

@linuxnow linuxnow commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Refs #131. The verbs only plugin-hostd answers are declared in its own contract directory, the daemon reads them from the rendered header, and the contract directory's files ship in a new noarch package, plugin-hostd-contract.

The declaration

data/verbs.json (omx-contract schema 3.3.0), installed as contract.d/3/plugin-hostd/verbs.json beside formats/clap.json and formats/lv2.json:

verb format plugin-hostd omx-clap-host mod-host
worker_list worker_list required
instance_info instance_info %i required
supervisor_reset supervisor_reset ... required
quarantine_clear quarantine_clear %s required
policy_set policy_set %s %s required
pool_config pool_config %s %i required
worker_env worker_env %s %s %s required
pin_set pin_set %s %s %s ... required
pin_clear pin_clear %s required
pin_accept pin_accept %s required
lv2_worker_set lv2_worker_set %s %s required
chain chain %i %i ... required required unsupported
chain_clear chain_clear %i required
chain_get chain_get %i required
descriptor_get descriptor_get %s required
panel_get panel_get %s required
preset_list preset_list %i optional optional unsupported
preset_get preset_get %i %i optional optional unsupported
pin_layout pin_layout %i (sender) optional unsupported

The replies are the README's, word for word. The matrix is the README's host-verbs columns: every verb the daemon answers itself is required of every profile, preset_list and preset_get are optional. PLUGIN_HOSTD_REPLY_CODES carries the 25 numbers of PHD_ERRORS (-501 to -531) that no other package names, as reply.plugin-hostd.* codes. One name per number: -3, -508, -510, -511, -513, -514, -517 and -902 are answered by both hosts and named once, by omx-clap-core's HOST_REPLY_CODES (reply.host.*). data/verbs.json requires omx-clap-core >= 0.22.0 and its verbs cite HOST_REPLY_CODES.instanceNonExists, .invalidOperation and .pinAbsent; plugin-hostd-contract requires omx-clap-core-contract >= 0.22.0, and the check stage build-requires it. add stays mod-host's verb and is not declared here.

The shared verbs

track_info, remote_pages, remote_page_get, param_info, pin_expect and the four note verbs, and the reply.host.* codes, are omx-clap-core's (FreeMixer/omx-clap-core#354). Until omx-clap-core-contract is published, this PR is validated against omx-clap-core's branch feat/host-verbs-contract, installed as 0.22.0 into a scratch contract directory and named through OMX_CONTRACT_PATH: the three packages validate together (146 items in 111 files, valid), links --check finds 0 problems, no verb is declared twice and no number has two names. CI, check-rendered and test-verbs-declared need that package; without it they refuse.

protocol.h keeps the words and formats of those nine verbs: the build needs nothing of omx-clap-core, only the check stage does (make check-no-pins). tests/verbs_declared.py holds them to omx-clap-core's declarations (8 formats, equal), resolves every verb's codes over both packages, and holds one name per number: no resp named by two codes, and each PHD_ERR_ number of protocol.h named by one of the two packages (36 numbers, 31 of protocol.h's, 6 of those omx-clap-core's). Once the package is published, the run reads it from the installed contract directory with no setting.

The header

make render-verbs writes include/plugin-hostd/plugin_hostd_host_verbs.h and plugin_hostd_vocabulary.h from the package as it installs; make check-rendered (in make test, %check and dh_auto_test) fails on any drift. protocol.h includes the verbs header; every PHD_VERB_* of a declared verb is gone from protocol.h, src/, tests/fake_host.c, tools/protocol-gen.c and fuzz/, replaced by OMX_VERB_*, and the PHD_VERBS rows take their reply from OMX_VERB_<VERB>_REPLY. protocol.h keeps the error numbers, the settings, the events, the placement and the prose. The generated README tables, man page and protocol/plugin-hostd.json do not change. tests/consumer.c compiles against plugin-hostd-devel and plugin-hostd-contract installed in a clean fedora:44.

Packages

file before now
/usr/share/omx-contract/contract.d/3/plugin-hostd/MANIFEST.json plugin-hostd-devel / plugin-hostd-dev plugin-hostd-contract (noarch / all)
.../plugin-hostd/formats/clap.json, formats/lv2.json plugin-hostd-devel / plugin-hostd-dev plugin-hostd-contract
.../plugin-hostd/verbs.json (new) plugin-hostd-contract
/usr/include/plugin-hostd/plugin_hostd_host_verbs.h, plugin_hostd_vocabulary.h (new) plugin-hostd-devel / plugin-hostd-dev

plugin-hostd and plugin-hostd-devel (plugin-hostd-dev) require plugin-hostd-contract at the same version-release; the deb Breaks and Replaces plugin-hostd-dev (<< ${source:Version}). Floors: omx-contract-devel (libomx-contract-dev) 3.3.0; the check stage needs the omx-contract command, 3.3.0. The CI file lists follow, and the DEB smoke checks the contract package's files, its architecture, its Breaks and Replaces and the Depends on it.

For the omx-panel lane: omx-panel reads formats/lv2.json (and clap.json) at run time; it requires plugin-hostd-contract >= 0.12.0 (deb plugin-hostd-contract) in place of plugin-hostd-devel / plugin-hostd-dev.

Tests, each sabotaged

tests/verbs_declared.py (make test-verbs-declared) drives the daemon in front of tests/fake-host: each verb plugin-hostd owes answers a line its declared format takes with its declared reply, and a malformed line and the lines it refuses by meaning with declared codes; the words of the binary the daemon answers without relaying them (29 of 205) are the declared verbs and mod-host's commands; a verb both hosts owe answers one line in one shape from the daemon and from the fake worker. It found the first declaration's -101 for an unknown instance; the daemon answers -3, now declared.

sabotage red
chain_get's format becomes chain_get %i %i verbs_declared
the no-such-chain code becomes -101 verbs_declared
plugin-hostd names -902 again verbs_declared (one name per number)
chain_get's handler is deleted verbs_declared
the daemon answers verb_sabotage itself verbs_declared
"chain_get" typed by hand in src/verbs.c verbs_contract

tests/perturbation.py renames instance_info in a scratch data/verbs.json: check-rendered and check-generated go red, and after render-verbs and gen the rebuilt daemon answers instance_where and not instance_info. make fuzz-run (60 s each, fuzz_command and fuzz_reply, no crash) and make fuzz-sabotage (13 mutants found) pass. make test passes in a fedora:44 container with the FreeMixer channel.

Not verified here

  • The mod-host README part of tests/verbs_contract.py (no mod-host checkout locally; CI's has one).
  • test-jack, test-jack2, the LV2 adapter run and the full make sabotage over jack (the five new arms ran).
  • The Debian build and its smoke, and the RPM job on aarch64; a local x86_64 rpmbuild -ba with the check stage passes.
  • Against omx-clap-core#354 at a1fcd5e, one check is red on its side: remote_pages declares only -3, and the daemon answers -902 for a line without its instance. With HOST_REPLY_CODES.invalidOperation added to remote_pages (not yet on #354), test-verbs-declared is green and every verbs and contract sabotage arm goes red. omx-clap-host answers that line few arguments, the protocol library's reply for any short line, not -902.
  • test-probe's a_process_an_lv2_plugin_left_in_its_own_session_is_gone_after_the_run failed in 2 of 5 local runs (an empty pid file); this branch changes nothing the probe runner builds from.
  • CI against a published omx-clap-core-contract, and the RPM and Debian builds with the new dependency on it: the package is not published yet.

data/verbs.json carries PLUGIN_HOSTD_VERBS, the verbs plugin-hostd adds to
mod-host's protocol and answers itself (worker_list, instance_info,
supervisor_reset, quarantine_clear, policy_set, pool_config, worker_env,
pin_set, pin_clear, pin_accept, lv2_worker_set, chain, chain_clear,
chain_get, descriptor_get, panel_get, preset_list, preset_get) and
pin_layout, which it sends a worker, with the format, the reply, the
refusals and what each host owes each one. PLUGIN_HOSTD_REPLY_CODES
carries the numbers PHD_ERRORS answers, -501 to -531, and the two mod-host
numbers the daemon answers for its own verbs, -902 and -101.

omx-contract 3.3.0 validates the package installed beside its own:
121 items in 92 files from 2 packages, valid; fmt --check is clean.
…ol.h

omx-contract renders data/verbs.json into
include/plugin-hostd/plugin_hostd_host_verbs.h (OMX_VERB_<VERB>, _FMT,
_REPLY, _CODES_INIT and the table of what each host owes each verb) and
plugin_hostd_vocabulary.h (the reply codes as strings). make render-verbs
writes them from the package as it installs, beside the installed contract
directory and OMX_CONTRACT_PATH; make check-rendered fails on any drift.
make install puts both beside protocol.h, which includes the verbs header.

The PHD_VERB_* defines of the daemon's own verbs are gone: every source,
the fake host, the generator and the fuzz harnesses read OMX_VERB_*, and
the PHD_VERBS and PHD_INSTANCE_VERBS rows take their word and their reply
from the render. protocol.h keeps add (mod-host's, with a placement),
pin_expect, the instance verbs a worker answers and the note verbs, which
omx-clap-core declares, and the error numbers, the settings, the events and
the prose of the tables. The generated README, man page and
protocol/plugin-hostd.json do not change.

tests/verbs_contract.py reads the rendered words too: no C string of src/,
fake_host.c or protocol-gen.c starts with one, nor one of fuzz/ or
protocol.h. tests/perturbation.py renames a verb in a scratch
data/verbs.json: check-rendered and check-generated go red, and after
render-verbs and gen the rebuilt daemon answers instance_where and not
instance_info.
… package

The files under share/omx-contract/contract.d/3/plugin-hostd (MANIFEST.json,
formats/clap.json, formats/lv2.json and now verbs.json) are read at run
time, so they leave plugin-hostd-devel and plugin-hostd-dev for a new
noarch package, plugin-hostd-contract on Fedora and Debian alike
(Architecture: all), at the same paths. plugin-hostd and plugin-hostd-devel
(plugin-hostd-dev) require it at the same version; the Debian package Breaks
and Replaces plugin-hostd-dev (<< ${source:Version}), which shipped them
before. The development package gains the two rendered headers.

The floor of omx-contract-devel (libomx-contract-dev) is 3.3.0, the first
schema with the verbs kind, and the check stage needs the omx-contract
command for make check-rendered, which %check and dh_auto_test now run.
The CI file-list checks follow: the RPM job lists the contract package and
the Requires of the other two, the clean root installs it, and the DEB smoke
checks its files, its architecture, its Breaks and Replaces and the
Depends on it.

A local rpmbuild -ba (fc44, check stage on) writes
plugin-hostd-contract-0.11.0-1.fc44.noarch.rpm with the four files and the
licence, and tests/consumer.c compiles against plugin-hostd-devel and
plugin-hostd-contract installed in a clean fedora:44.
mod-host's ERR_INSTANCE_NON_EXISTS is -3 (host-errors.h); -101 is
ERR_LV2_INVALID_URI. On the daemon's socket instance_info 99,
quarantine_clear 99, preset_list 99 and preset_get 99 0 answer resp -3, so
the declaration said a number no reply carries. tests/verbs_declared.py,
the next commit, found it: four refused lines red against -101, green
against -3. The render follows: OMX_VERB_INSTANCE_INFO_CODES_INIT is
{ -3, -902 }.
tests/verbs_declared.py (make test-verbs-declared, part of make test) reads
data/verbs.json and omx-clap-core's declarations, from its package in the
first directory of OMX_CONTRACT_PATH that holds one or else the installed
contract directory, and drives the daemon in front of tests/fake-host:

- each of the 18 verbs plugin-hostd owes, and the shared ones it owes,
  answers a line its declared format takes with its declared reply (an
  optional one may refuse with a code it declares), and a malformed line
  and the lines its meaning refuses with codes it declares;
- the words of the binary the daemon answers without relaying them to its
  worker (29 of 205) are the declared verbs and mod-host's commands, no more;
- a verb both hosts owe answers one line in one shape from the daemon and
  from the fake worker run on ports of its own;
- protocol.h's formats of the shared verbs are omx-clap-core's.

Without omx-clap-core's package the run prints PENDING, takes the shared
verbs protocol.h names in their place and names that source.

tests/sabotage.py breaks it five ways, each red and then restored: a
declared format (chain_get %i %i), a declared code (-101 for -3), a deleted
handler (chain_get), an undeclared verb the daemon answers itself, and a
declared verb typed by hand in src/verbs.c (tests/verbs_contract.py). The
scan fixture moves from tests/daemon_test.py to tests/scan_fixture.py, which
both tests read.
The verbs the daemon adds now live in verbs.json of the package
plugin-hostd-contract, rendered into plugin_hostd_host_verbs.h, which
protocol.h includes; the rest of the protocol stays declared in protocol.h.
…y.host.*

-3, -508, -510, -511, -513, -514, -517 and -902 are answered by both hosts and
declared by omx-clap-core's HOST_REPLY_CODES (omx-clap-core#354). data/verbs.json
no longer names them a second time: it requires omx-clap-core >= 0.22.0 and its
verbs cite HOST_REPLY_CODES.instanceNonExists, .invalidOperation and .pinAbsent.
PLUGIN_HOSTD_REPLY_CODES keeps the 25 numbers of -501 to -531 no other package
names. The rendered header follows (same resp numbers, reply.host.* names), and
plugin_hostd_vocabulary.h drops the eight duplicate strings.

tests/verbs_declared.py resolves a verb's codes over both packages, fails when
omx-clap-core's package is unreadable (the declaration requires it), and holds
one name per number: no resp named by two codes, and every PHD_ERR_ number of
protocol.h named by one of the two packages (36 numbers, 31 of protocol.h's, 6
of those omx-clap-core's). The -3 sabotage arm moves to -522; a new arm names
-902 again in plugin-hostd and goes red on that check.

Validated against omx-clap-core#354 at a1fcd5e installed as 0.22.0 in a scratch
directory named by OMX_CONTRACT_PATH: omx-contract 3.3.0 validate, 146 items in
111 files from 3 packages, valid; render --check byte-identical; links --check
0 problems.
verbs.json refers to omx-clap-core's reply.host.* codes, so a reader of
plugin-hostd's package reads omx-clap-core's too: plugin-hostd-contract
requires omx-clap-core-contract >= 0.22.0 (deb: Depends), and the check stage
build-requires it for check-rendered and test-verbs-declared (%if %{with check},
<!nocheck>; check-no-pins stays green). BUILDING.md and the README say which
package names which number.
@linuxnow
linuxnow merged commit 1e0f328 into main Oct 26, 2026
36 checks passed
@linuxnow
linuxnow deleted the feat/131-verbs-contract branch October 26, 2026 16:55
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.

1 participant