chore(surface): fold to agentbase-mixin-flatten branch (comp-attr enrich + allowlist cleanup)#57
Open
mjerris wants to merge 7 commits into
Open
chore(surface): fold to agentbase-mixin-flatten branch (comp-attr enrich + allowlist cleanup)#57mjerris wants to merge 7 commits into
mjerris wants to merge 7 commits into
Conversation
…rich + allowlist cleanup Bring the rust port to green against porting-sdk fix/agentbase-mixin-flatten-fold (diff-side Class A mixin-flatten + B1 composition-attr folds + newer oracle). Emission (enumerate_surface.py): - Add a composition-attribute enrich mirroring the oracle's _enrich_composition_attributes: import self-only class-ref-returning members from the reference signature oracle onto the matching port class, gated on the port's OWN port_signatures.json recording that member (keeps the two oracles consistent by construction). Surfaces the swml_verbs_generated / post_prompt_generated struct-field members Rust records method-less — retires 207 phantom omissions and stops those classes folding to the gen-type pseudo-module. - Promote PromptObjectModel.sections / Section.subsections public struct fields (the pub-fn parser misses fields); un-drop PomBuilder.pom (oracle now records it). - Drop the 5 composition-delegate re-exposures Rust flattens onto AgentBase (render_swml/get_contexts/get_raw_prompt/create_tool_token/get_global_data) — the delegate class already carries the reference-matching copy, so the AgentBase copy was a phantom addition after the family fold. Allowlist cleanup: - Delete 292 dead PORT_OMISSIONS + 40 dead PORT_ADDITIONS non-REST entries the folds retired; keep entries live for either the folded SURFACE diff or the unfolded SIGNATURE diff (incl. class-level coverage). - 5 new impossible: omissions (private-field idioms: agents/logger/security/ loaded_skills/skill_manager) + 18 new agentbase-family additions (genuine port-only granular setters/accessors). - Freeze all signalwire.rest.* *Resource/*Namespace entries pending the deferred spec-driven REST base+subclass parity pass (do not delete/rename). - Add the ALLOWLIST_DISCIPLINE §1 header to PORT_OMISSIONS.md + PORT_ADDITIONS.md. Coordinated-With: porting-sdk@fix/agentbase-mixin-flatten-fold Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NqhUoqrbptHNS3cypq9s6t
… in surface The composition-attribute enrich surfaced `Section.main` (a POM `list<SWMLMethod>` field the reference oracle records), so the bare name `main` now exists in port_surface.json. The DOC_AUDIT_IGNORE.md `main:` entry — excluding the doc-local `fn main` entry point in getting-started code fragments — claimed "not a port symbol", which IGNORE-LEDGER-VERIFY correctly flagged as a now-false non-existence rationale. Reword the rationale to describe the doc-local `fn main` code-fragment token positively (a Rust program entry point written inline in the example), distinct from the `Section.main` POM field, without any absence claim. The doc-audit exclusion of the `fn main` fragment token stays; only the stale rationale is corrected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NqhUoqrbptHNS3cypq9s6t
… dead entries Wave-3 cleanup on the allowlist-fold branch, now that the spec-driven REST crud_bases mechanism is in the oracle. REST crud_bases emission: - enumerate_surface.py now emits the port's OWN top-level `crud_bases` map in port_surface.json (49 resources), sourced from the generator sidecar (rest_signatures.json), never hand-written. The surface diff folds a CRUD method (list/create/get/update/delete/paginate) on any class either the reference or the port declares a crud_base for, so rust's resources beyond the reference's 25 (Messages, PubSub, ImportedNumbers, …) fold without per-op allow-list entries. Symbol-neutral: the class shape is unchanged, only the new top-level map is added. Dead-entry retirement: - PORT_ADDITIONS.md: deleted 274 frozen `signalwire.rest.*` CRUD additions now folded by the crud_bases map. Kept 70 genuine port-infra additions (RestClient namespace accessors, _base CrudResource/HttpClient/SignalWireRestError helpers, _request_options builders, http_client transports, *_with_options overloads). - PORT_OMISSIONS.md: deleted 213 dead `signalwire.rest.*` omissions (symbols no longer in the oracle / folded by crud_bases). Accessor omissions (24 composition-attr entries): all KEPT as genuine non-name omissions — rust exposes the OPERATIONS (add_skill, get_basic_auth_credentials, register_verb_handler) but not the composed OBJECT under any name; agents/ loaded_skills have a matching method already (a rename would orphan it); logger/ security/skill_manager/verb_registry have no per-instance member at all. Zero renames were warranted. DUAL-GATE: AgentBase.skill_manager and AgentServer.app are surface-oracle-EXCLUDED (so the surface fold covers them) but the SIGNATURE oracle still records them, so they stay in PORT_OMISSIONS with an impossible: reason — the DRIFT gate keys unfolded and needs the AgentBase/AgentServer-scoped copies. SURFACE-DIFF + signature DRIFT both PASS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NqhUoqrbptHNS3cypq9s6t
Emit the @DataClass public fields the reference oracle now records into the Rust surface + signature oracles: - relay.event.* typed-event accessor fields (already added; committed here). - AI-Chat DTO public struct fields (CLASS B field-emit via the enumerator): ChatResponse.{text,conversation_id,user_event}, ChatLog.{messages,call_timeline}, ConversationInfo.{id,status,initial_message}. Rust exposes these as bare `pub` struct fields (a field is not a `pub fn`, so the parser misses them); promote them onto the surface via PUBLIC_FIELD_MEMBERS and synthesize the reference-shaped 0-param field-read accessors in build_ai_chat_signatures(). - CollectEvent: the reference field is `final`; the Rust accessor is spelled `is_final` (reserved-word clash) and folded to `final` via the METHOD_RENAMES table. Delete the now-dead `CollectEvent.is_final` PORT_ADDITIONS.md line (the surface emits `final`). - RequestOptions.{timeout,retries,retry_on_status,retry_backoff}: the reference records these as 0-param dataclass field accessors; Rust exposes each as a chained builder setter over the same `pub` field. Excuse as builder-setter idiom in PORT_SIGNATURE_OMISSIONS.md, matching the existing `abort_signal` entry (same shape, same field). Surface diff + signature diff both exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NqhUoqrbptHNS3cypq9s6t
Collaborator
Author
|
Coordinated set root: signalwire/porting-sdk#120 (branch That PR carries the shared oracle/diff folds this branch is pinned to ( Merges as a set, porting-sdk first. No merge before approval. |
…questOptions setter additions)
Allow-list fold campaign, rust lane.
PORT_OMISSIONS.md — 4 dead `logger` omissions deleted. The surface oracle no
longer records the per-instance `logger` attribute (owner ruling 2026-07-24:
logging is a MODULE-LEVEL capability ports may reach however their language
does; contract = the 5 free functions in `signalwire.core.logging_config`).
The entries excused symbols that are no longer in the reference, so
diff_port_surface flagged them DEAD:
AgentServer.logger, SkillBase.logger, SkillManager.logger, SkillRegistry.logger
PORT_ADDITIONS.md — 4 dead `RequestOptions` builder-setter additions deleted:
RequestOptions.{retries,retry_backoff,retry_on_status,timeout}
These carried the canonical banned rationale ("builder setter idiom for the
same field", ALLOWLIST_DISCIPLINE §7). Rust has BOTH `pub timeout: Option<f64>`
(the field) and `pub fn timeout(self, s) -> Self` (the setter over it), spelled
identically — so the enumerator already emits ONE member per field matching the
oracle's `RequestOptions.{abort_signal,retries,retry_backoff,retry_on_status,
timeout}`. The lines excused nothing and were pure paperwork.
Verification (fast diffs, no build):
diff_port_surface.py --reference python_surface.json --port-surface
port_surface.json --omissions PORT_OMISSIONS.md --additions PORT_ADDITIONS.md
-> exit 0: "port matches Python reference (2550 symbols; 33 excused
omissions, 528 excused additions)"
audit_docs.py --root . --surface port_surface.json --ignore DOC_AUDIT_IGNORE.md
-> exit 0: "docs/examples reference only known symbols (1758 resolved / 3705
total)" — zero unresolved symbols, no accessor-fold doc drift on rust.
KNOWN RED, not fixable in this lane: diff_port_signatures.py now reports 3
missing-port drifts (AgentServer.logger / SkillManager.logger /
SkillRegistry.logger). The owner-ruled logger exclusion landed in
porting-sdk `scripts/enumerate_python.py` (surface oracle) but NOT in
`scripts/enumerate_python_signatures.py`, so python_signatures.json still
records all 4 members keyed on the same
`class:signalwire.core.logging_config.get_logger` return the surface
enumerator excludes on. The signature diff consumed PORT_OMISSIONS.md via
--surface-omissions, so deleting the dead surface lines unmasked it. The fix
is the one-line mirror in the signature enumerator (porting-sdk, orchestrator-
owned); creating a signature omission here is forbidden (ALLOWLIST_DISCIPLINE
§0a).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y1fEcuaivoN1poPGS75jAy
Collaborator
Author
|
Re-running CI against porting-sdk |
Rust expresses a wide many-optional-kwarg constructor as an OPTIONS STRUCT: the reference's `AgentBase.__init__(name, route, host, port, ...)` becomes `AgentBase::new(AgentOptions::new(name).route(..).host(..))`. Those struct FIELDS are the construction parameter set, so they satisfy the §10 contract rather than being N port-only additions plus one blanket `__init__` omission. `build_construction` emits a NAME-KEYED top-level `construction` node from two sources, in precedence order: the class's own `__init__` (Rust `new`) params, then its options struct's public fields. The fluent `with_*`/setter methods fold onto the field they set — they add no capability the field does not already carry, the same field+setter precedent RequestOptions established. `required` is derived from the options struct's OWN constructor rather than from `Option<T>`-ness: `AgentOptions::new(name)` takes `name` and defaults the other nine, and a `Default`-only struct demands nothing — so a defaulted scalar (`auto_answer: bool`) is correctly optional despite its non-Option type. `basic_auth_user`/`basic_auth_password` canonicalize to the reference's single `basic_auth` tuple param via the adapter rename table (ADAPTER_CONTRACT rule 3); Rust splits the pair because struct literals have no anonymous-tuple idiom. 124 classes / 241 params. Purely additive — `modules` is byte-identical, so no existing signature comparison changes. DRIFT and SURFACE-DIFF both exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y1fEcuaivoN1poPGS75jAy
…fab options idiom
AgentBase implemented its own state but never wired the params the reference
FORWARDS to collaborators, so 13 documented constructor params were unreachable
from construction even though the underlying capability already existed in the
port (17 config-file references, 30 schema-validation references, all dead).
Wired, each to the same collaborator the reference uses:
* schema_path / schema_validation -> Service -> SchemaUtils
(agent_base.py:205-207, swml_service.py:186). Service now holds an
Arc<SchemaUtils> override, built ONLY when the caller asks for a non-default
schema; default construction keeps borrowing the process-wide shared
default, so the parse-once hot path is unchanged.
* config_file -> Service -> SecurityConfig (swml_service.py:139) and ->
AgentBase's own _load_service_config (agent_base.py:359-382). Added
SecurityConfig::with_config_file, porting _load_config_file key for key
including the nested auth.basic.{user,password} path and the reference's
defaults -> env -> config-file priority order.
* token_expiry_secs -> SessionManager (agent_base.py:247).
* agent_id, native_functions, record_format, record_stereo,
default_webhook_url, suppress_logs, enable_post_prompt_override,
check_for_input_override, trust_proxy_for_signature stored on the agent.
Two wire/behavior defects found and fixed along the way:
* record_format defaulted to "wav" and record_stereo to false, where the
reference defaults "mp4"/true. The identical reference program emitted a
different recording on the wire.
* webhook signature validation unconditionally honored X-Forwarded-Proto /
X-Forwarded-Host. Those headers are set by whoever reaches the agent, so an
attacker able to reach it directly could sign a URL for a hostname of their
choosing, inject it, and have the signature validate. The reference defaults
trust_proxy_for_signature=False for exactly this reason. Signature URL
reconstruction now goes through resolve_signature_base, which honors
operator config (SWML_PROXY_URL_BASE / manual_set_proxy_url) always but the
forwarded headers only on explicit opt-in. Advertised web_hook_url
construction is unaffected.
AgentBase::clone also rebuilt its Service from ServiceOptions, silently dropping
the schema-utils override and resolved SecurityConfig; it now clones the Service
directly.
Prefabs: FAQBot/Receptionist/Survey/Concierge/InfoGatherer took flat positionals
that made every param required, so valid reference programs did not port
(FAQBotAgent(faqs) needed five arguments here). Each now takes an options struct
whose `new` takes exactly the reference's required positionals and defaults the
rest. Concierge's venue_info map is flattened to the reference's real params
(from_venue_info retained for callers holding a JSON blob), and survey's
brand_name / conclusion / max_retries are now wired into the prompt and global
data as the reference wires them rather than accepted and dropped.
Enumerators: the options-struct family folds at emit (EMISSION COVERS IDIOM)
rather than being recorded as surface additions — an options struct IS its
target class's reference __init__ kwargs, and the construction contract in
port_signatures.json is what proves the parameter set matches. Same fold for the
seven new field-read getters, which stand in for reference instance attributes
that Python records as no surface at all. That made 18 PORT_ADDITIONS entries
dead; deleted them. No new omission or addition entries.
Construction drift, this brief's scope: AgentBase 13 missing params -> 0,
SWMLService 3 -> 0, prefabs 21 required-flips + 14 missing/extra params -> 0.
Fleet-wide 210 -> 166.
Verification: 2045 tests pass (18 new construction-contract tests), FMT clean,
LINT clean, diff_port_signatures.py and diff_port_surface.py both exit 0,
enumerator regen byte-stable.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y1fEcuaivoN1poPGS75jAy
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.
Brings the Rust port to green against porting-sdk
fix/agentbase-mixin-flatten-fold(diff-side Class A mixin-flatten + B1 composition-attribute folds + the newer python oracle).
Emission (
scripts/enumerate_surface.py)_enrich_composition_attributes:import self-only class-ref-returning members from the reference signature oracle onto the
matching port class, gated on the port's OWN
port_signatures.jsonrecording that member(keeps the two oracles consistent by construction; never invents surface). Surfaces the
swml_verbs_generated/post_prompt_generatedstruct-field members Rust recordsmethod-less — retires 207 phantom omissions and stops those classes folding to the
gen-typepseudo-module while the reference (now carrying members) does not.PromptObjectModel.sections/Section.subsectionspublic struct fields (thepub fnparser misses bare fields); un-dropPomBuilder.pom(oracle now records it).AgentBase(
render_swml/get_contexts/get_raw_prompt/create_tool_token/get_global_data) — thedelegate class already carries the reference-matching copy, so the AgentBase copy read as a
phantom addition after the family fold.
Allow-list cleanup
PORT_OMISSIONS+ 40 deadPORT_ADDITIONSnon-REST entries thefolds retired; keep entries live for either the folded SURFACE diff or the unfolded
SIGNATURE diff (incl. class-level coverage —
diff_port_signatures.pydoes not apply thefamily fold, so it still needs the unfolded
AgentBase.<m>keys).impossible:omissions (private-field idioms:agents/logger/security/loaded_skills/skill_manager— Rust holds these private + exposes renamed accessors) and18 new
agentbase-familyadditions (genuine port-only granular setters/accessors).signalwire.rest.**Resource/*Namespaceentries left as-is pending thedeferred spec-driven REST base+subclass parity pass (per coordinator direction — do not
delete/rename).
ALLOWLIST_DISCIPLINE§1 header toPORT_OMISSIONS.md+PORT_ADDITIONS.md.Verification
scripts/suites/surface.py --port rust→ all 9 SURFACE rules PASS (SIGNATURES, DRIFT,SURFACE-FRESH, SURFACE-DIFF, RELAY-VERB-RESULT-LOCK, GEN-TYPE-DEGENERACY, ROUTE-COLLISION,
GEN-IDIOM, SEMVER-DIFF). Regeneration verified deterministic. No Rust source touched, so the
cargo TEST/LINT/BEHAVIORAL gates are unaffected by this change.
Coordinated-With: porting-sdk@fix/agentbase-mixin-flatten-fold
🤖 Generated with Claude Code
https://claude.ai/code/session_01NqhUoqrbptHNS3cypq9s6t