Skip to content

1.2.50

Choose a tag to compare

@github-actions github-actions released this 08 Sep 06:54
· 215 commits to main since this release
Immutable release. Only release title and notes can be modified.
  • Push alerts are sealed with post-quantum encryption wherever the daemon
    can. Every alert is end-to-end encrypted, so the relay that forwards it
    never sees plaintext, but the x25519 sealing behind that is the kind a
    future quantum computer could break, and traffic recorded today could be
    decrypted then. A device paired under the xwing suite closes that
    window: its alerts are sealed with X-Wing (ML-KEM-768 + X25519), a
    hybrid of post-quantum and classical key exchange, through HPKE in base
    mode (HKDF-SHA256, AES-256-GCM). The push extra carries the
    cryptography library that seals it on every platform with a wheel, so
    post-quantum sealing needs no further install step. GET /whoami names
    the suites a daemon can seal to as sealableSuites; the app pairs under
    xwing when it is listed, moves an existing x25519 pairing up on its
    own once a daemon starts advertising xwing, and moves an xwing
    pairing back down if its daemon stops sealing it. The post-quantum key
    material costs 1136 bytes of the fixed notification budget, so an
    xwing alert carries a shorter log tail. A daemon without the library
    refuses xwing pairings and says so at startup, x25519 pairings are
    unchanged, and the wire construction is normative in
    docs/relay-protocol.md.
  • Post-quantum sealing ships in every release binary and container image
    whose platform can compile it. Where PyPI publishes no cryptography
    wheel, CI builds the library from source against an OpenSSL 3.5 it
    installs or builds: for the Linux builds without a wheel (including the
    glibc linux-armv6 for the Raspberry Pi 1 and Zero), for
    windows-arm64, for the FreeBSD, OpenBSD, NetBSD, and illumos builds,
    and for every image platform. A build that fails to compile the library
    ships without the suite, and each one that succeeds proves itself with a
    real X-Wing seal before it is frozen in. Intel
    macOS and 32-bit Windows carry cryptography 48.x, the last line with a
    wheel for them. The linux-ppc64le binary needs glibc 2.28 rather than
    2.17, the floor of the only ppc64le wheel. The illumos-amd64 binary
    also carries the push reporter itself, with libsodium from the OmniOS
    extra publisher. linux-mips64le and linux-armel seal x25519 only,
    because no Rust toolchain exists for their architectures.
  • A daemon event alert whose subject or message is empty leaves that field
    out of the sealed plaintext instead of sending it as null, which is what
    the relay protocol's field contract specifies.
  • The reaper learns of a finished job through a done callback on that job's
    wait task, and filing the completion is one list append however many jobs
    are running. Draining 500 completions one at a time with 500 jobs running
    measures 6 ms locally against 50 ms.
  • A bare cronstable --version prints the version before it builds the
    argument parser and its subparsers. The command measures 54 ms locally
    against 64 ms.
  • The SLA pass walks a memoized list of the jobs that carry an sla block
    and reads the latch map to find a latch left on a job whose block a
    reload removed. One pass over 2,000 jobs with 20 SLA blocks measures
    0.02 ms locally against 0.15 ms; over 10,000 jobs with 100 blocks,
    0.09 ms against 0.79 ms.
  • The Prometheus scrape carries a rendered block on each shared per-job
    label set, renders small integral values from a table filled on the
    first scrape, builds each sample line as one string, and keeps its
    sorted job order between scrapes. Two renders of a 500-job exposition
    with run counters measure 8.7 ms locally against 13 ms.
  • The calendar feed folds each line once as it builds it, describes each
    distinct schedule without an H item once, and stops a capped entry
    before converting the fire it drops. A 500-entry, seven-day feed
    measures 25 ms locally against 43 ms.
  • The configuration parser forks a strictyaml position pointer with one
    list copy, passes a value holding no $ through the interpolation walk
    without a call, and hands every job with a clean schedule the same empty
    findings list. A 300-job parse measures 96 ms locally against 108 ms, an
    interpolation walk over 2,000 references 41 ms against 49 ms, and a full
    garbage collection with 100,000 jobs resident 34 ms against 99 ms.
  • The filesystem state store writes each atomic file through its raw
    descriptor, opened in binary mode on every platform, lists a records or
    documents root with scandir so the directory test reads each entry's
    own type, sorts each stream listing once in the order the caller reads it,
    and takes its try-lock through the one lock routine's non-blocking lane.
    Twenty repeat listings of an unchanged 2,000-record stream measure 83 ms
    locally against 103 ms, and a garbage-collection sweep over 2,000 unkept
    streams 103 ms against 169 ms.
  • The dashboard's schedule engine jumps a restricted hour, minute, or
    second field straight to its next listed value, keeps one collator for
    every name sort, memoizes each schedule's prose, counts the running,
    failing, ok, and paused jobs in one pass, and checks a fleet poll against
    the response text it parsed. The log drawer keeps its search pattern
    compiled across streamed lines, caches each line's stripped and lowercased
    text, writes the match count only when it changes, and shows bad regex
    in its place for a pattern that doesn't compile. Counting the matches in
    a 5,000-line buffer measures 0.04 ms locally against 0.28 ms, and a cold
    week walk over 500 schedules 1.75 ms against 4.2 ms.
  • The terminal dashboard caches short SGR sequences and their bounded
    rewrites per theme. Discarded control sequences and oversized rewrites
    stay out of the cache. The log drawer, the DAG log tab, and the tail view
    bind their style helpers and stream markers once per frame. Restyling a
    5,000-line drawer measures 17 ms locally against 25 ms, and a drawer
    scroll walk with steady repaints 67 ms against 101 ms.
  • Config load rejects a job whose name matches a DAG's schedule job
    (dag:<dag name>), including collisions across files and includes.
    Other dag: job names and classic crontabs named dag are valid.
  • A failed cluster peer poll removes the peer from agreement, including
    failures while parsing telemetry. Invalid telemetry fields are discarded
    while the peer's membership observation is processed.

Performance vs 1.2.49

Gate: passed. Every metric stayed inside its regression limit.

Both versions ran interleaved on one runner. Time metrics compare the best round of each and memory metrics the median. A negative change means faster or smaller.

A regression gates only when it exceeds both its declared limit and 2 noise bands. The +- column is that band: the round-to-round scatter of the two sides, combined in quadrature.

All benchmark results (97 metrics)
Benchmark 1.2.49 1.2.50 Change Noise +- Gate (eff.)
loop.stall_completions_500 110.26 ms 14.92 ms -86.5% 1.0% 25%
webui.log_count_5k 660.0 us 90.0 us -86.4% 4.4% 303% (declared 25%)
webui.week_walk_500 7.65 ms 3.50 ms -54.2% 1.2% 25%
ical.render_500x7d 93.49 ms 51.46 ms -45.0% 2.5% 15%
prometheus.render_500 30.04 ms 17.74 ms -40.9% 2.1% 33.29% (declared 15%)
tui.drawer_paint_5k 223.63 ms 137.50 ms -38.5% 0.4% 15%
tui.log_restyle_5k 53.01 ms 32.64 ms -38.4% 1.3% 18.87% (declared 15%)
mem.gc_pause_100k 177.71 ms 126.70 ms -28.7% 4.0% 25%
startup.version 68.91 ms 54.48 ms -28.0% 0.2% 25%
state.gc_sweep_2k_streams 59.98 ms 44.64 ms -25.6% 1.7% 25%
config.parse_yaml_300 269.36 ms 202.56 ms -24.8% 0.9% 15%
config.parse_yaml_3k 2.677 s 2.026 s -24.3% 1.0% 15%
config.reload_warm_50 61.15 ms 47.44 ms -22.4% 0.8% 25%
config.reload_warm_include_50 129.67 ms 101.46 ms -21.8% 0.5% 25%
cluster.parse_summaries_6k 110.28 ms 86.99 ms -21.1% 0.6% 15%
schedule.reseed_local_20k 118.99 ms 94.86 ms -20.3% 1.1% 15%
cronexpr.test_match_200k 33.60 ms 26.94 ms -19.8% 2.2% 29.76% (declared 15%)
config.interp_2k 97.18 ms 78.35 ms -19.4% 0.4% 15%
webui.radar_walk_500 470.0 us 390.0 us -17.0% 0.0% 425.5% (declared 25%)
schedule.due_pass_100k 18.23 ms 15.44 ms -15.3% 1.8% 54.85% (declared 25%)
config.reload_gc_100k 2.849 s 2.417 s -15.2% 1.2% 25%
startup.validate_config_100 256.12 ms 223.60 ms -13.6% 0.2% 25%
mem.jobconfig_2k 1.70 MB 1.49 MB -12.6% 0.1% 29.42% (declared 15%)
startup.job_set_id_100 259.99 ms 229.53 ms -12.6% 0.4% 25%
cronexpr.occurrences_1k 16.18 ms 14.19 ms -12.3% 2.1% 61.8% (declared 15%)
schedule.suggest_slot_5k 4.90 ms 4.31 ms -12.2% 6.2% 203.9% (declared 15%)
state.list_records_warm 144.04 ms 126.70 ms -12.0% 0.5% 15%
cronexpr.next_simple 43.81 ms 38.72 ms -11.6% 1.9% 22.83% (declared 15%)
schedule.reseed_100k 232.53 ms 205.71 ms -11.5% 1.9% 15%
json.roundtrip_3k 658.32 ms 588.55 ms -10.6% 0.9% 15%
mem.rss_version 16.22 MB 14.62 MB -9.9% 0.5% 25%
schedule.next_fires_2k 29.82 ms 27.00 ms -9.5% 1.2% 33.53% (declared 15%)
json.roundtrip_orjson_3k 235.90 ms 213.96 ms -9.3% 0.5% 15%
startup.import_config 104.61 ms 97.11 ms -8.6% 0.4% 25%
state.fanout_gather_100 27.15 ms 24.81 ms -8.6% 4.9% 36.83% (declared 25%)
mcp.handle_200 144.32 ms 132.40 ms -8.3% 0.5% 15%
schedule.duplicates_20k 19.32 ms 17.74 ms -8.2% 5.2% 51.75% (declared 15%)
cluster.job_owner_2k 65.18 ms 60.21 ms -7.6% 3.1% 15%
schedule.pressure_20k_48h 18.21 ms 16.88 ms -7.3% 5.9% 54.93% (declared 15%)
cronexpr.next_complex 17.28 ms 16.05 ms -7.1% 1.1% 57.87% (declared 15%)
schedule.cold_build_100k 543.51 ms 505.88 ms -6.9% 0.8% 15%
dag.plan_claim_10k 17.92 ms 16.70 ms -6.8% 3.6% 55.81% (declared 15%)
loop.stall_metrics_2000 29.36 ms 27.55 ms -6.2% 1.8% info
state.mutate_document_1k 227.91 ms 215.20 ms -5.6% 0.5% 25%
cronexpr.next_dst_2k 36.70 ms 34.71 ms -5.4% 1.9% 27.24% (declared 15%)
state.artifact_list_churn 1.70 ms 1.61 ms -5.3% 4.6% 293.7% (declared 25%)
schedule.lint_250_zoned 7.94 ms 7.54 ms -5.0% 1.0% 126% (declared 15%)
push.seal_500 99.47 ms 94.65 ms -4.8% 0.4% 15%
webui.render_fleet_15x400 25.21 ms 23.99 ms -4.8% 0.8% 25%
state.artifact_get_newest 24.34 ms 23.26 ms -4.5% 1.0% 25%
state.derive_max_warm 285.97 ms 273.33 ms -4.4% 0.4% 15%
config.jobconfig_3k 70.34 ms 67.28 ms -4.4% 2.3% 15%
dag.finish_fanin_1k 4.25 ms 4.07 ms -4.2% 1.2% 117.6% (declared 25%)
webui.render_rows_500 17.63 ms 16.93 ms -4.0% 0.5% 25%
state.list_records_2k 30.31 ms 29.18 ms -3.7% 1.6% 32.99% (declared 15%)
dag.mapped_drain_256 32.30 ms 31.12 ms -3.6% 2.3% 30.96% (declared 25%)
state.derive_max_cold 27.58 ms 26.71 ms -3.1% 2.1% 36.26% (declared 15%)
redact.clean_20k 21.16 ms 20.53 ms -3.0% 1.8% 47.25% (declared 15%)
startup.import_cronexpr 28.42 ms 28.77 ms +2.8% 0.5% 25%
config.parse_crontab_1k 12.21 ms 11.89 ms -2.6% 1.4% 81.9% (declared 15%)
state.list_documents_600 71.06 ms 69.22 ms -2.6% 0.8% 16.89% (declared 15%)
loop.idle_wake_rate 21.90 ms 21.35 ms -2.5% 1.5% 25%
state.depends_on_past_gate 3.60 ms 3.51 ms -2.5% 2.9% 55.59% (declared 25%)
state.boot_rehydrate_populated 49.63 ms 48.45 ms -2.4% 1.0% 20.15% (declared 15%)
dag.adopt_scan_500 108.77 ms 106.24 ms -2.3% 1.3% 25%
dag.list_dags_warm 1.09 ms 1.11 ms +2.3% 2.3% 183.7% (declared 25%)
loop.stall_jobs_500 21.54 ms 21.11 ms -2.0% 0.6% info
webui.render_term_5k 130.35 ms 127.80 ms -2.0% 1.1% 25%
state.lease_renew_200 134.15 ms 131.54 ms -1.9% 1.8% 37.27% (declared 25%)
state.kv_roundtrip_200 184.99 ms 181.63 ms -1.8% 1.5% 15%
dag.build_chain_10k 29.40 ms 28.95 ms -1.5% 2.6% 34.01% (declared 15%)
job.stream_capture_120k 45.70 ms 45.09 ms -1.3% 1.7% 21.88% (declared 15%)
startup.import_daemon 176.76 ms 178.65 ms +1.2% 0.8% 25%
dag.build_layered_10k 49.79 ms 50.35 ms +1.1% 3.1% 20.09% (declared 15%)
cronexpr.parse_complex 24.25 ms 24.51 ms +1.1% 1.3% 41.23% (declared 15%)
webapi.sse_burst_20k 58.14 ms 58.74 ms +1.0% 1.2% 15%
redact.adversarial_10k 37.63 ms 37.32 ms -0.8% 0.8% 26.57% (declared 15%)
redact.secrets_5k 21.02 ms 21.14 ms +0.6% 1.0% 47.57% (declared 15%)
job.report_noop_100k 48.81 ms 49.07 ms +0.5% 1.9% 15%
dag.list_runs_warm 12.91 ms 12.84 ms -0.5% 1.6% 25%
cronexpr.parse_simple 44.93 ms 45.15 ms +0.5% 1.3% 22.26% (declared 15%)
state.append_1k 724.81 ms 721.67 ms -0.4% 2.3% 15%
webapi.auth_scope_20k 93.66 ms 93.29 ms -0.4% 0.5% 15%
cluster.fleet_view_15x400 90.85 ms 90.50 ms -0.4% 0.5% 25%
dag.advance_quiescent_1k 73.63 ms 73.35 ms -0.4% 0.7% 25%
startup.python_baseline 17.32 ms 17.36 ms +0.2% 0.4% info
webapi.jobs_payload_500 59.04 ms 58.92 ms -0.2% 0.9% 16.94% (declared 15%)
dag.advance_quiescent_chain 72.65 ms 72.51 ms -0.2% 1.0% 25%
mem.rss_daemon_import 36.12 MB 36.06 MB -0.2% 0.2% 25%
resources.monitor_stop_100 288.04 ms 288.44 ms +0.1% 1.9% 25%
fingerprint.job_set_id_10k 297.42 ms 297.05 ms -0.1% 0.5% 15%
tui.log_search_20k 16.34 ms 16.33 ms -0.1% 0.9% 61.18% (declared 15%)
statsd.emit_2k 14.74 ms 14.74 ms +0.0% 0.9% 67.84% (declared 25%)
webui.append_line_5k 15.0 us 15.0 us +0.0% 4.4% 25%
webapi.jobs_bytes_500 181.42 KB 181.42 KB +0.0% 0.0% 15%
webapi.jobs_gzip_500 5.19 KB 5.19 KB +0.0% 0.0% 15%
mem.crontab_10k 2.80 MB 2.80 MB +0.0% 0.0% 17.85% (declared 15%)

What's Changed

  • Bump the github-actions group with 6 updates by @dependabot[bot] in #14

Full Changelog: 1.2.49...1.2.50