Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
9bf7c48
fix(logging): core get_logger returns a Logger, not a bool status flag
mjerris Jul 27, 2026
dcb269a
fix(lint): clear 20 clang-tidy violations my include exposed in logge…
mjerris Jul 27, 2026
da8326e
wave6: retire dead ctor entries (ALLOWLIST_DISCIPLINE §495, shared-di…
mjerris Jul 27, 2026
60cd267
Merge remote-tracking branch 'origin/fix/get-logger-returns-a-logger'…
mjerris Jul 27, 2026
95641ab
feat(parity): expose the 7 derived caller-observable ctor attributes
mjerris Jul 27, 2026
2c3c04f
fix(lint): clean clang-tidy findings in the new remove_xpaths code
mjerris Jul 27, 2026
f0b5df5
fix(skills): all 18 builtins were double-registered — the LIVE copies…
mjerris Jul 27, 2026
3f8fe97
fix(security): insecure SWAIG tools got an UNAUTHENTICATED per-tool w…
mjerris Jul 27, 2026
13b5678
fix(tools): state_dump aborted on a duplicate registration MY OWN com…
mjerris Jul 27, 2026
3376969
feat(signatures): enumerate real parameter DEFAULT VALUES from the he…
mjerris Jul 28, 2026
4eacff0
fix(defaults): 8 default VALUES diverged from the reference — a defau…
mjerris Jul 28, 2026
281ca7f
fix(signatures): fold C++'s zero-value sentinel to null — 60 params r…
mjerris Jul 28, 2026
1827392
fix(signatures): model absence and follow the reference's shape — 18 …
mjerris Jul 28, 2026
50cdd9c
fix(signatures): fold the options-carrier idiom — 9 methods hid behin…
mjerris Jul 28, 2026
2c6cf6d
test(relay): pin all seven API-name -> wire-key remaps, not just the two
mjerris Jul 28, 2026
977ec1f
fix(auth): carry the credential surface — scheme was a real missing f…
mjerris Jul 28, 2026
8a1fd6d
fix(surface): fold the synthesized __init__ the oracle now records — …
mjerris Jul 28, 2026
10ef953
fix(relay): delete the invented Call::prompt alias — play_and_collect…
mjerris Jul 28, 2026
1b61c5c
chore(release): set the SemVer floor to 3.0.0 and re-anchor its surfa…
mjerris Jul 28, 2026
bc853f0
chore(changelog): consolidate the never-published 3.x entries into 3.0.0
mjerris Jul 28, 2026
c992f20
docs: add .version-frozen — version and SemVer floor pinned at 3.0.0
mjerris Jul 28, 2026
99c4661
skills(mcp_gateway): add verify_ssl, WIRED to real server-cert verifi…
mjerris Jul 28, 2026
30f9ec0
fix(security): mint SWAIG tool tokens with PADDED urlsafe base64 + wi…
mjerris Jul 28, 2026
86d1a24
docs: describe the registry contract, not the porting audit that foun…
mjerris Jul 28, 2026
7a66b79
fix(datamap): emit the reference's HYPHENATED nomatch-output wire key
mjerris Jul 28, 2026
db30481
chore(gate): re-baseline the TYPE-EROSION ratchet onto the corrected …
mjerris Jul 29, 2026
92e8b55
fix(logging): put the control-char scrub ON the emission path, and ma…
mjerris Jul 29, 2026
9481c85
docs: fix prompt_add_subsection snippets and the declaration they wer…
mjerris Jul 29, 2026
d2a4b11
fix(ci): rebuild wait_liveness_dump — 820d500 silently dropped it and…
mjerris Jul 29, 2026
4ea907f
fix(ledger): delete 36 dead omissions, reword 7 misworded-but-real
mjerris Jul 29, 2026
07054db
fix(skills): datasphere_serverless sent its search payload on a key t…
mjerris Jul 29, 2026
94f29b9
fix(datamap): upper-case the webhook method on the wire, matching the…
mjerris Jul 29, 2026
54abe7f
ci(gates): schedule BEHAVIORAL-STRICT-RENDER, CA-VAR, TLS-VERIFY, SEC…
mjerris Jul 29, 2026
38551d2
chore(doc-surface): re-pin floor 90.2 -> 95.6 after forward decls lef…
mjerris Jul 29, 2026
ca38de0
docs(surface): document the last 19 public types; pin DOC-SURFACE flo…
mjerris Jul 29, 2026
34d820d
ci(doc-surface): flip cpp from report-only to BLOCKING now that it is…
mjerris Jul 29, 2026
9995cb9
ci(doc-surface): drop cpp's skip-with-pass guard — "BLOCKING" was con…
mjerris Jul 29, 2026
540c31e
test(security): pin get_ssl_context_kwargs to python's exact key set
mjerris Jul 29, 2026
c6fd88e
fix(swml): emit play as url "say:<text>", not a text key (#180 sweep)
mjerris Jul 29, 2026
47c07ee
feat(datamap)!: remove DataMap::body() — the builder wrote a key noth…
mjerris Jul 30, 2026
3cc519a
fix(swml): restore AIObject.multilingual to the vendored schema
mjerris Jul 30, 2026
7e462c2
fix(swml)!: route every verb emission through the validating path (#194)
mjerris Jul 30, 2026
74e0f56
fix(swaig)!: enforce `secure` on the serverless transport, and refuse…
mjerris Jul 30, 2026
12ce32b
test(swml): pin that Hangup.reason accepts values outside its const-u…
mjerris Jul 30, 2026
8e58661
ci: gate that the committed port_signatures.json matches a fresh regen
mjerris Jul 30, 2026
52a49d9
docs: write the public docs for C++ users, not for readers of another…
mjerris Jul 30, 2026
6471631
fix(serverless): let the token query-string parser move its return value
mjerris Jul 30, 2026
a08c34a
style: format tests/ and examples/ at the same bar as the shipped lib…
mjerris Jul 30, 2026
fe9fd56
fix(enumerate_surface): delete the dead duplicate AuthMixin projectio…
mjerris Jul 30, 2026
60c27e8
fix(examples): stop discarding [[nodiscard]] results the SDK marks lo…
mjerris Jul 30, 2026
fd1a364
fix(tests): make the ephemeral-port pickers fail loud instead of retu…
mjerris Jul 30, 2026
7a86c45
fix(tests): stop swallowing errors that made real failures unexplainable
mjerris Jul 30, 2026
0eda3bd
style(lint): mechanical clang-tidy fixes across tests/, tools/ and ex…
mjerris Jul 30, 2026
d4d5a31
fix(enumerate_surface): abort on a header parse failure instead of dr…
mjerris Jul 30, 2026
cabf58e
lint(python): add a ruff config and burn scripts/ to zero
mjerris Jul 30, 2026
9f95201
fix(tests): assert SkillBase::setup() instead of discarding its result
mjerris Jul 30, 2026
2857e1e
fix(examples,tools): guard main() so an escaping exception is not std…
mjerris Jul 30, 2026
98cabe9
fix(examples): parse env/argv numbers with sto* instead of atoi/atof
mjerris Jul 30, 2026
761aa2c
build: mark vendored deps/ as a SYSTEM include directory
mjerris Jul 30, 2026
50e660a
fix(tests): guard thread bodies, drop system(), finish the setup() sweep
mjerris Jul 30, 2026
7ef3207
ci: widen FMT + LINT to the whole first-party tree, add a PY-LINT gate
mjerris Jul 30, 2026
8b8076d
docs: re-sync the README include blocks and the doc-audit ignore ledger
mjerris Jul 30, 2026
88b72fc
fix(generate_rest_tests): format the generated tests at emit
mjerris Jul 30, 2026
a118f06
chore: allowlist ruff.toml at the repo root (ROOT-HYGIENE)
mjerris Jul 30, 2026
0d4c555
feat(swml)!: give on_swml_request the `request` parameter the referen…
mjerris Jul 30, 2026
9bc2a9a
chore(surface): regenerate signature + surface artifacts for the on_s…
mjerris Jul 30, 2026
2d605f8
build: enable -Wall on the shipped library, and drop the examples' -W…
mjerris Jul 30, 2026
ae017a6
ci(lint): bring tests/ under clang-tidy, with exactly three checks sc…
mjerris Jul 30, 2026
7472079
fix(pylint): pin the ruff config, and make its path rules path-robust
mjerris Jul 30, 2026
f5a7894
refactor(contexts)!: make attach_tool_name_supplier non-public
mjerris Jul 30, 2026
1a0aa42
chore(surface): regenerate artifacts after hiding attach_tool_name_su…
mjerris Jul 30, 2026
fc07655
fix(enumerate_signatures): make type-translation failures fail loud B…
mjerris Jul 30, 2026
ae2a1c6
lint(tests): scope out bugprone-unchecked-optional-access — 13 false …
mjerris Jul 30, 2026
39b8e04
fix(enumerate_signatures): project the builtin skills' SkillBase hook…
mjerris Jul 30, 2026
f9afcf5
fix(relay)!: refuse a plaintext downgrade when SIGNALWIRE_RELAY_CA_FI…
mjerris Jul 30, 2026
5bfd3d5
fix(enumerator): fold base-identical skill hooks to the reference shape
mjerris Jul 30, 2026
a15d2dc
fix(enumerate_surface): gate the skill projection on the LIVE surface…
mjerris Jul 30, 2026
2ed3ed7
regen(swaig): refresh the SWAIG payloads the spec re-vendors staled
mjerris Aug 4, 2026
96c1e29
ci: pin ruff — the one unpinned linter, on the line below the pinned …
mjerris Aug 4, 2026
4bf0f34
gen(swaig): emit the SwaigAction/SwaigResponse envelope the generator…
mjerris Aug 5, 2026
b49dc27
docs(swml): the on_swml_request override snippets lost a parameter on…
mjerris Aug 5, 2026
e8ea94b
perf(ci): fix the stale-cache LINT blowup + restore ccache to cpp's o…
mjerris Aug 5, 2026
ef304ee
perf(ci): make both caches path-insensitive and identical locally and…
mjerris Aug 5, 2026
b67ce5f
fix(signatures): derive gen-payload surface from the spec, not the or…
mjerris Aug 6, 2026
ce2d086
gen(relay): read the combined spec through the shared adapter (R11)
mjerris Aug 6, 2026
f9a65ea
gen(swaig): regenerate SWAIG payloads after the spec re-vendor
mjerris Aug 7, 2026
88d99b2
gen(signatures): regenerate port_signatures.json after the SWAIG payl…
mjerris Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 12 additions & 3 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,18 @@ Checks: >
-readability-redundant-access-specifiers

# Scope to first-party code only: vendored headers under deps/ (httplib.h,
# json.hpp, nlohmann/) are NEVER linted. The filter matches both src/ and
# include/ under the signalwire-cpp tree. (CI is Linux; on macOS Apple libc++
# json.hpp, nlohmann/) are NEVER linted. (CI is Linux; on macOS Apple libc++
# header drift can emit a trailing note — the header-filter keeps findings
# scoped to our own headers regardless.)
HeaderFilterRegex: 'signalwire-cpp/(src|include)/'
#
# Widened 2026-07-30 alongside scripts/run-lint.sh, from (src|include) to every
# first-party tree, so headers pulled in from tools/, tests/ and the example
# trees are analysed the same way. tests/ matters especially: 123 test .cpp files
# are #included into test_main.cpp, so without tests/ here their findings would be
# filtered out as "not the main file" and the gate would be VACUOUS over them. deps/ remains excluded because we do not own it — and
# is now ALSO excluded at the compiler, via CMake marking it a SYSTEM include
# directory, which is the only lever that works for clang-diagnostic-* entries
# (those are compiler warnings surfaced through clang-tidy, so this regex never
# applies to them).
HeaderFilterRegex: 'signalwire-cpp/(src|include|tools|tests|examples|rest|relay)/'
WarningsAsErrors: '*'
2 changes: 1 addition & 1 deletion .doc_surface_floor
Original file line number Diff line number Diff line change
@@ -1 +1 @@
90.2
100.0
110 changes: 99 additions & 11 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,52 @@ jobs:
with:
python-version: '3.14'

- name: Install build deps (cmake + g++ + OpenSSL 3 headers)
- name: Install build deps (cmake + g++ + OpenSSL 3 headers + ccache)
run: |
sudo apt-get update
sudo apt-get install -y cmake g++ libssl-dev
sudo apt-get install -y cmake g++ libssl-dev ccache

# ccache — COMPILER cache, persisted across runs. Distinct from ctcache below
# and non-overlapping: ctcache memoizes clang-tidy STATIC-ANALYSIS results,
# ccache memoizes COMPILER object output. This nightly job is where the two
# heaviest compilations live — the TEST gate's build/ and PACKAGE-SMOKE, which
# does a full Release build+install of the whole library into a scratch prefix
# and measured 13m07s on the 2026-08-05 nightly (run 30990423636, 08:53:51 ->
# 09:06:58). ccache was removed in 1fe7b2c because it "can't touch the LINT
# gate"; that is true of LINT and wrong for these builds, and with it absent
# every runner printed "note: ccache not found" and built fully cold.
# Measured locally (8 cores, 130 TUs, the PACKAGE-SMOKE Release shape):
# cold 344.7s -> warm 3.0s (130/130 direct hits) at an unchanged build path,
# 32.0s when only preprocessed-mode hits apply. NOTE the path caveat:
# package_smoke.py builds in a PID-unique sandbox (.sw-tmp/package-smoke-cpp-<pid>),
# so run-to-run it is the preprocessed-mode figure that applies, not the 3.0s one.
# CMakeLists.txt already availability-gates ccache as CMAKE_{C,CXX}_COMPILER_LAUNCHER.
# Both caches below key off a UTC date stamp; see the staleness note on the
# ctcache restore for why. Computed once here so the two agree exactly even
# across a UTC midnight boundary mid-job.
- name: Cache date stamp (rotates the restore-key daily)
id: cachedate
run: 'date -u +date=%Y-%m-%d >> "$GITHUB_OUTPUT"'

# Same daily-rotated restore-key tier as ctcache below, for the same
# scope-before-recency reason (see the long note there).
- name: Restore compiler cache (ccache)
uses: actions/cache/restore@v6
with:
path: ~/.cache/ccache
key: ccache-cpp-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
ccache-cpp-${{ runner.os }}-d${{ steps.cachedate.outputs.date }}-
ccache-cpp-${{ runner.os }}-

# clang-tidy result cache (vendored ctcache, scripts/clang_tidy_cache.py).
# The LINT gate — clang-tidy over 65 TUs — is cpp's CI wall-clock driver
# (~824s serial, ~252s after the xargs fan-out). ccache does NOT help it
# (that's compilation; this is static analysis), which is why the old ccache
# cache-persistence here was dead weight — removed. Instead persist ctcache's
# per-TU result cache: an UNCHANGED TU (source, its headers, checks, config
# all identical) returns the cached result without running clang-tidy.
# The LINT gate — clang-tidy over 65 TUs — was cpp's CI wall-clock driver
# before this cache (~824s serial, ~252s after the xargs fan-out); it now
# completes in ~14s on this workflow. ccache does NOT help it (that's
# compilation; this is static analysis), which is why this SEPARATE cache
# exists. Persist ctcache's per-TU result cache: an UNCHANGED TU (source, its
# headers, checks, config all identical) returns the cached result without
# running clang-tidy.
# Stable key + run_id suffix so each run restores the most recent cache and
# saves an updated one; source-hashing the key would defeat the point (we
# WANT it to persist across source changes and only miss on the changed TUs).
Expand All @@ -128,13 +162,33 @@ jobs:
# prior step, and every cpp run is currently red on the pre-existing
# spec-coupling — so a combined cache would never populate. The separate
# save step below runs with if: always().
#
# STALENESS FIX (2026-08-05). Actions resolves restore-keys by SCOPE FIRST,
# recency second: a run sees its own ref's caches and the default branch's,
# and an own-ref match wins even when the main-scope one is far newer. So a
# long-lived branch pins itself to whatever entry it wrote long ago and never
# advances. Measured on THIS workflow, same gate, same branch:
# run 30908553939 (2026-08-04) restored ctcache-cpp-Linux-30465863814,
# written 2026-07-29 on refs/heads/wave6/ctor-dunder-fold -- SIX DAYS
# stale, chosen over a refs/heads/main entry from 3h earlier that was
# visible to it -- and LINT took 12m45s (12:35:14 -> 12:47:59).
# run 30990423636 (2026-08-05) restored a 1-day-old entry: LINT took 14s.
# 55x, entirely from which store got restored. Adding more bare-prefix
# fallbacks cannot fix it -- the own-ref scope is consulted before them.
# The fix is to make the stale entry UNMATCHABLE by the first-choice key:
# a date stamp ahead of the bare prefix, so today's runs agree on a key that
# an older branch entry cannot satisfy, falling through to the undated prefix
# only when no recent store exists. ctcache is content-addressed per TU, so
# restoring an older store is always CORRECT, just slower -- this changes
# which store is preferred, never the findings.
- name: Restore clang-tidy cache (ctcache)
id: ctcache_restore
uses: actions/cache/restore@v6
with:
path: ~/.cache/ctcache
key: ctcache-cpp-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
ctcache-cpp-${{ runner.os }}-d${{ steps.cachedate.outputs.date }}-
ctcache-cpp-${{ runner.os }}-

# The FMT (clang-format) + LINT (clang-tidy) gates need the gate tools
Expand All @@ -152,6 +206,15 @@ jobs:
- name: Install pinned clang-format + clang-tidy 18.1.8 + clang-18 compiler
run: |
pip install "clang-format==18.1.8" "clang-tidy==18.1.8"
# ruff drives the PY-LINT gate (scripts/*.py). Declared here as well
# as in scripts/_env.sh so a CI runner has it, per AGENT_RULES §7.
# PINNED EXACT: an unbounded `pip install ruff` resolves the newest release
# at CI time, so a ruff release that adds a rule or changes a format
# heuristic reds FMT/LINT on a commit that was green locally. Keep in
# lockstep with SW_RUFF_VERSION in scripts/_env.sh.
pip install "ruff==0.15.21"
ruff --version
ruff --version | grep -qw '0\.15\.21' || { echo "FATAL: ruff is not the pinned 0.15.21" >&2; exit 1; }
sudo apt-get install -y clang-18
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100
Expand Down Expand Up @@ -214,17 +277,42 @@ jobs:
# here (not in env:) so $HOME expands to an ABSOLUTE path — ctcache does
# NOT expanduser CTCACHE_DIR, so a literal "~" would create a bogus dir.
export CTCACHE_DIR="$HOME/.cache/ctcache"
# ccache's compiler cache. ~/.cache/ccache is already ccache's default,
# but set it EXPLICITLY so the dir the restore/save steps name can never
# drift from the dir ccache actually uses (e.g. if a future runner image
# ships an XDG_CACHE_HOME or a /etc/ccache.conf that relocates it — then
# we would be caching an empty dir and silently getting cold builds while
# the workflow still looked correct). Same absolute-path reason as above.
export CCACHE_DIR="$HOME/.cache/ccache"
# NOTE: CCACHE_BASEDIR/CCACHE_NOHASHDIR (which make ccache path-insensitive
# so PACKAGE-SMOKE's PID-unique sandbox can still hit direct mode — this
# workflow's largest gate at 13m07s, one full cold Release build+install) are
# set in scripts/_env.sh, NOT here — deliberately, so a local run and a CI run
# get the SAME cache behaviour. Setting them here off $GITHUB_WORKSPACE would
# apply on a runner only, and local devs would silently get preprocessed-only
# hits. _env.sh keys off $REPO, which it resolves CWD-independently.
bash scripts/run-ci.sh

# Save the ctcache store even if the gate failed (the LINT gate still ran +
# populated it). Unique run_id key so every run persists an updated cache;
# the next run's restore-keys prefix picks up the most recent.
# populated it). The saved key carries the SAME date stamp the restore-keys
# look for, so a later run today prefers a store written today over an older
# branch entry; run_id keeps every save unique so concurrent runs never
# collide on one key.
- name: Save clang-tidy cache (ctcache)
if: always()
uses: actions/cache/save@v6
with:
path: ~/.cache/ctcache
key: ctcache-cpp-${{ runner.os }}-${{ github.run_id }}
key: ctcache-cpp-${{ runner.os }}-d${{ steps.cachedate.outputs.date }}-${{ github.run_id }}

# Save the compiler cache on the same if: always() terms and for the same
# reason — the builds ran and populated it even when a later gate went red.
- name: Save compiler cache (ccache)
if: always()
uses: actions/cache/save@v6
with:
path: ~/.cache/ccache
key: ccache-cpp-${{ runner.os }}-d${{ steps.cachedate.outputs.date }}-${{ github.run_id }}

- name: Record green marker for this input triple
run: 'echo green > .nightly-green-marker'
Expand Down
Loading