fix(api): runtime settings, recorder, logs and datapath (C4) - #39
Merged
Merged
Conversation
… engine-defined Only observed_at and source are required; log.level and the replay ring are independent, so a level-only engine is valid. Fixed 64-record minimums leave the schema and engines advertise min_* bounds. Flow capability ceilings are the engine's limits, flows.recording gains on_demand, and honk's attachment and demand timing moves to the honk notes.
… attachments entry_capacity may be null for an unbounded cache and loses the 100,000 cap. Log target is nullable and resources.logs.filters lists the supported GET /logs filters. eBPF attachments carry kind interface or cgroup, so cgroup hooks such as dae's are reportable.
action keeps pass, redirect, hold and drop as the core set and accepts other lowercase engine values, which clients show as they are. honk's NFQUEUE actions, UDP decision token and Clash-mode override move to the honk notes.
Zakkaus
force-pushed
the
fix/contract-runtime-settings
branch
from
September 28, 2026 17:40
03b81fd to
2a16334
Compare
…ments - attachments gain an `other` kind with a free `hook`; the list may be partial - `flows.recording` reports policy (off/on/on_demand), not current capture - `grace_remaining_seconds` is the engine's attachment grace, optional - RecorderMode (PATCH) and RecorderState.mode (GET string) documented apart - DNS eviction and fill ratio only with a positive capacity - flow capability retention is at least 1 second - GET /logs declares 422; enumerations list filters and min_* fields - flow-steps drops the honk Clash-mode example; honk notes list the actions honk emits today
…current capabilities
Zakkaus
force-pushed
the
fix/contract-runtime-settings
branch
from
September 28, 2026 17:40
2a16334 to
e30a67b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Contract PR C4 of the API revision plan: runtime settings, recorder, logs and datapath (F8, F14, F15, F17, F18, F39, F45). Plan decision Q7 applies.
Five commits: runtime settings and recorder; DNS capacity, log filters and eBPF attachments; flow-step actions; review fixes (recorder policy, grace scope, partial attachments, DNS ratio, retention floor, logs 422); wording. Rebased on
honkafter C3 (#38). Schema tests cover each new conditional requirement.F15, Q7: runtime settings sections are optional
RuntimeSettingsrequires onlyobserved_atandsource. A value appears whenresources.runtime_settings.fieldslists it; an engine may also report values it cannot change. Insidelog,levelandbuffered_recordsare independent, so{"log": {"level": "info"}}is a complete PATCH and a valid GET body (newlevel_onlyexamples). The fixed 64-record minimums leave the schema (minimum 1); engines advertiselogs.min_buffered_records,dns_log.min_recordsandflows.min_flows, absent meaning 1. An empty section is still invalid.resources.flows.retention_secondsis now at least 1 and a PATCH may always set 1, the same fixed floor the settings table already stated. This is the smaller change; the rings keep theirmin_*fields because 64 is honk's floor, while every engine can retain for 1 second.min_buffered_records: 64,min_records: 64andmin_flows: 64, which honk's PATCH enforces (settings.rspatch_with).log.levelinfields, reports{"log": {"level": ...}}, and applies a PATCH withlogger.SetLogger/SetLevelas the reload worker already does (cmd/run_reload_worker.go:115-124). No ring, flow or recorder fields.F14, Q7: recorder state is
{allowed, mode, active}pluson_demandRecorderStatekeepsallowed,modeandactive.autonow means "record on demand"; what counts as demand and how long it lasts is engine-defined. Insiderecording, each recorder appears when itsrecord_*field is listed;eventsis optional. honk's attachment and flow-demand rules (60-second grace, which requests renew it) move to the new "Runtime settings in honk" section of the honk notes.resources.flows.recordingreports policy, not current capture:offwhen the recorder is not allowed or its mode is off,onwhen the mode is on,on_demandwhen the mode is auto whether or not a client creates demand now.recording.flows.activereports capture.RecorderModeis the PATCH value (true,false,"auto");RecorderState.modeis the GET string (on,off,auto). Both descriptions and the PATCH section now say so.grace_remaining_secondsis the engine's attachment grace only, optional; which recorders follow it is engine-defined and a recorder may keep its own demand timer. No per-recorder grace.settings.rs:240-243reports the attachment timer only). HC: report the policy:on_demandin auto mode,onwhen pinned,offwhen not allowed or pinned off (todaytypes.rscapabilitiesreportson/offfrom the active flag).record_*field, omitsrecordingandgrace_remaining_seconds, and reportsflowsunavailable orrecording: off.F8: flow capability ceilings are the engine's limits
resources.flows.max_flowsandretention_secondsare described as the most a runtime-settings PATCH may set, not the current values (discovery schema, runtime-status and flows pages).types.rscapabilitiesusessettings.flow_limits(), the current values).logs.max_buffered_recordsanddns_log.max_recordsalready report the 512 maximum.F17: honk constants are not contract limits
DnsCacheUsage.entry_capacityisUInt64 | null(null: no entry limit or unknown) and loses the 100,000 cap.dns-cache.mdnow ties eviction and theentries / entry_capacityratio to a positive capacity; a null or zero capacity supports no ratio.operations.max_replay_keyswas already advertised in C1; it is the field merged.md F17 callsmax_idempotency_keys, and the C1 name stays. The 12-hour session constant moved to the honk notes in C3 (docs: access model, geodata lifecycle and one SSRF policy (C3) #38), so this PR leavesauth.mdalone.operations.max_replay_keys: 1024(operations.rsMAX_TOMBSTONES).control/dns_controller_cache.goenforceDnsCacheCapacityLocked).F18: flow-step actions have a core set and an extension point
DatapathStepData.actionispass,redirect,hold,drop, or an engine-defined lowercase token (^[a-z][a-z0-9_]*$, at most 64 characters); clients show an unknown value as it is. The NFQUEUE hold/arm/verdict prose, the UDP decision token, the token allocator and the Clash-mode wording move to "Flow steps in honk".mode_overridekeeps its values with neutral wording; its schema no longer names honk's Clash mode.drop(control/udp_endpoint/mod.rs:263,retirement.rs:70,control/connection/udp.rs:443,446) and the engine-definedactivate_directandactivate_proxy(control/connection/udp.rs:410,472). "Flow steps in honk" lists them as engine-defined values and says honk records the activation, not each hold, arm, verdict and publication step.F39: log
targetis nullable and filters are advertisedLogRecord.targetisstring | null.resources.logs.filters(required when available, always containslevel) lists the GET/logsfilters;targeton an engine that does not list it returns422 unsupported_value, and atargetfilter never matches a null target. GET/logsnow declares that 422 with an example.flows.md,logs.mdandcapabilities.mdlistfiltersand themin_*fields.filters: [level, target](logs.rscapability).target: nulland the adapter advertisesfilters: [level].F45: eBPF attachments are typed, and the list may be partial
EbpfAttachmentrequireskind: interface | cgroup | other. An interface attachment requiresinterfaceanddirection; a cgroup attachment requirescgroup(v2 path relative to the mount); anotherattachment requires a freehookdescription. Each kind rejects the other kinds' fields.attachmentslists what the engine checks and may be partial. The example shows all three.kind: interface(datapath.rsAttachment).interfaceand its cgroup programs (sock_create,connect4,sendmsg4and the rest,control/control_plane_core_bind.go:305-310) askind: cgroup, cgroup: "/". Its sockmap verdict program (control/control_plane_core_bind.go:392-407) and fentry/kprobe accounting (control/tcp_offload_hook.go:151-165) arekind: otherwith ahookdescription, or are left out of the partial list.Checks
npx -y yarn@1.22.22 check:contract: bundle, lint and 81 tests pass. New or changed tests: optional settings sections and the level-only request, recorder state andon_demand, advertised minimums, log filters and nullable target, nullable DNS capacity, attachmentkindconditionals includingother, datapath step actions, the flow retention floor, the logs 422.The HC rows are recorded in the drift ledger for the honk follow-up.