Skip to content

fix(bindings): refcount Pool to fix teardown panic - #352

Merged
wemeetagain merged 5 commits into
mainfrom
gr/binding-pool-refcount
May 11, 2026
Merged

fix(bindings): refcount Pool to fix teardown panic#352
wemeetagain merged 5 commits into
mainfrom
gr/binding-pool-refcount

Conversation

@GrapeBaBa

@GrapeBaBa GrapeBaBa commented May 7, 2026

Copy link
Copy Markdown
Contributor

Motivation

Reproduces on main and every binding-feature branch (#165, #346, #351): any process that holds a BeaconStateView at module scope panics during process exit:

thread N panic: incorrect alignment
src/persistent_merkle_tree/Node.zig:387:9 in unref
src/ssz/tree_view/chunks.zig:38:30 in deinit
src/ssz/tree_view/container.zig:97:49 in clearChildrenDataCache
src/state_transition/cache/state_cache.zig:102:26 in deinit

Process exits with code 134 (SIGABRT) instead of 0.

Root cause: NAPI env cleanup hook (napi_add_env_cleanup_hook) fires before module-level JS holders of native objects are finalized. The previous cleanup callback unconditionally called pool.state.deinit(), freeing the Node.Pool's MultiArrayList storage. Live BeaconStateView instances rooted by module-level const had not yet been finalized; when their finalizers eventually ran, the chained pool.unref(self.root) walked freed memory and panicked.

Module-scope is the standard pattern for benchmark fixtures (@chainsafe/benchmark + perf tests). Without the fix, every such test exits non-zero even when the bench itself succeeds.

Description

Wrap Node.Pool in the existing RefCount(T) (src/state_transition/utils/ref_count.zig):

  • Module init holds ref = 1.
  • Each BeaconStateView that owns a cached_state holds another ref.
  • pool.state.deinit() releases the module ref but only actually destroys the pool when the count reaches zero — deferring destruction past every live view's finalizer.

Order in BeaconStateView.deinit:

  1. cached_state.deinit() — does all the pool.unref(...) calls
  2. pool_rc.unref() — releases this view's pool ref; if last, real pool.deinit runs here

GrapeBaBa added 2 commits May 7, 2026 20:59
NAPI env cleanup hooks fire before module-level JS holders of native
objects (e.g. `const seedState = createFromBytes(...)`) get finalized.
The previous unconditional `pool.state.deinit()` in cleanup freed the
Pool's MultiArrayList while live `BeaconStateView` instances still
held references. When their finalizers later ran, the chained
`pool.unref()` walked freed memory and panicked with "incorrect
alignment" — process exited 134 / SIGABRT.

Wraps `Node.Pool` in the existing `RefCount(T)`. Module init holds
ref=1; each `BeaconStateView` that owns a `cached_state` holds
another. `pool.state.deinit()` releases the module ref but only
actually destroys the pool when the count reaches zero, deferring
teardown past every `BeaconStateView` finalizer.

- `state_transition/root.zig`: export `RefCount`
- `bindings/napi/pool.zig`: wrap pool, expose `pool()` and `poolRc()`
- `bindings/napi/BeaconStateView.zig`: hold a `pool_rc` alongside
  `cached_state`, ref on each constructor that builds one, unref in
  `deinit` after `cached_state.deinit` finishes its `pool.unref` calls.

Adds `bindings/test/teardown.test.ts`: spawns a subprocess that creates
a module-scope `BeaconStateView` and exits, expects exit 0 and no
"panic:" on stderr. Reproduces the bug on main; passes with this fix.
@GrapeBaBa
GrapeBaBa requested a review from a team as a code owner May 7, 2026 13:10
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical teardown panic occurring in native bindings when BeaconStateView instances are held at the module scope. By implementing a reference counting wrapper for the Node.Pool, the system now correctly defers pool destruction until all active views have been finalized, ensuring memory safety during NAPI environment cleanup.

Highlights

  • Reference Counting for Node.Pool: Introduced a reference counting mechanism for the Node.Pool to ensure it remains alive until all dependent BeaconStateView instances are finalized, preventing premature memory deallocation.
  • NAPI Teardown Fix: Updated the NAPI environment cleanup hook to release the module's reference to the pool rather than unconditionally destroying it, resolving SIGABRT panics during process exit.
  • Regression Testing: Added a new integration test that verifies module-scope BeaconStateView instances do not cause panics during process teardown.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces reference counting for the shared Node.Pool used by BeaconStateView to prevent 'incorrect alignment' panics during NAPI environment cleanup at process exit. The pool.zig module now wraps the pool in a RefCount structure, and BeaconStateView instances hold a strong reference to this pool for their lifetime. A new teardown test ensures that module-scope views exit cleanly. Feedback focuses on adhering to the repository's style guide regarding proper acronym capitalization (e.g., renaming PoolRc to PoolRC) and increasing assertion density to verify that the pool is initialized before access.

Comment thread bindings/napi/pool.zig

const default_pool_size: u32 = 0;

pub const PoolRc = RefCount(Node.Pool);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the style guide (Rule 224), acronyms should use proper capitalization. Since RC stands for Reference Count, it should be capitalized as PoolRC.

pub const PoolRC = RefCount(Node.Pool);
References
  1. Use proper capitalization for acronyms (VSRState, not VsrState). (link)

Comment thread bindings/napi/pool.zig
pub const State = struct {
pool: Node.Pool = undefined,
initialized: bool = false,
pool_rc: ?*PoolRc = null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the type name to PoolRC to adhere to the acronym capitalization rule.

    pool_rc: ?*PoolRC = null,

Comment thread bindings/napi/pool.zig
if (self.pool_rc != null) return;
var pool_value = try Node.Pool.init(allocator, default_pool_size);
errdefer pool_value.deinit();
self.pool_rc = try PoolRc.init(allocator, pool_value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the type name to PoolRC to adhere to the acronym capitalization rule.

        self.pool_rc = try PoolRC.init(allocator, pool_value);

Comment thread bindings/napi/pool.zig
Comment on lines +40 to +42
pub fn pool(self: *State) *Node.Pool {
return &self.pool_rc.?.instance;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The style guide (Rule 51) requires asserting function arguments and invariants. Adding an explicit assertion here improves safety and follows the 'fail-fast' principle.

    pub fn pool(self: *State) *Node.Pool {
        std.debug.assert(self.pool_rc != null);
        return &self.pool_rc.?.instance;
    }
References
  1. Assert all function arguments and return values, pre/postconditions and invariants. (link)

Comment thread bindings/napi/pool.zig
Comment on lines +44 to 46
pub fn poolRc(self: *State) *PoolRc {
return self.pool_rc.?;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Rename the function to poolRC and update the return type to PoolRC to adhere to the acronym capitalization rule (Rule 224). Additionally, add an assertion for the pool initialization invariant.

    pub fn poolRC(self: *State) *PoolRC {
        std.debug.assert(self.pool_rc != null);
        return self.pool_rc.?;
    }

/// `cached_state`. Released in `deinit` AFTER `cached_state.deinit` finishes
/// its `pool.unref` calls, so the pool stays alive even if the module's
/// NAPI env cleanup hook fired before this view's JS finalizer.
pool_rc: ?*pool.PoolRc = null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the type reference to PoolRC to match the updated naming convention in pool.zig.

pool_rc: ?*pool.PoolRC = null,

const slot_value = fork_types.readSlotFromAnyBeaconStateBytes(byte_slice);
const fork_seq = config.state.config.forkSeq(slot_value);
state.* = try AnyBeaconState.deserialize(allocator, &pool.state.pool, fork_seq, byte_slice);
state.* = try AnyBeaconState.deserialize(allocator, pool.state.pool(), fork_seq, byte_slice);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add an assertion to verify that the shared pool is initialized before use, as required by the style guide's assertion density and safety rules (Rule 51).

    std.debug.assert(pool.state.pool_rc != null);
    state.* = try AnyBeaconState.deserialize(allocator, pool.state.pool(), fork_seq, byte_slice);

return .{ .cached_state = cached_state };
return .{
.cached_state = cached_state,
.pool_rc = pool.state.poolRc().ref(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the call to poolRC() to match the renamed function in pool.zig.

        .pool_rc = pool.state.poolRC().ref(),


try st.processSlots(allocator, napi_io.get(), post_state, slot_value, .{});
return .{ .cached_state = post_state };
return .{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add an assertion to verify that the shared pool is initialized before returning a new view, ensuring the invariant holds and increasing assertion density.

    std.debug.assert(pool.state.pool_rc != null);
    return .{

return .{ .cached_state = post_state };
return .{
.cached_state = post_state,
.pool_rc = pool.state.poolRc().ref(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the call to poolRC() to match the renamed function in pool.zig.

        .pool_rc = pool.state.poolRC().ref(),

@wemeetagain
wemeetagain merged commit 23b2f68 into main May 11, 2026
30 checks passed
@wemeetagain
wemeetagain deleted the gr/binding-pool-refcount branch May 11, 2026 18:57
spiral-ladder added a commit that referenced this pull request May 21, 2026
@github-actions github-actions Bot mentioned this pull request Jul 30, 2026
wemeetagain pushed a commit that referenced this pull request Aug 19, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.0.0](v0.1.2...v1.0.0)
(2026-08-19)


### Features

* add `state.getBuildersLength()` binding
([#472](#472))
([be2b5ab](be2b5ab))
* **beacon-node:** add block state cache and checkpoint datastore
([#452](#452))
([2145faa](2145faa))
* bindings to `getExpectedWithdrawals` and native tweaks
([#350](#350))
([f47bc66](f47bc66))
* **bindings:** add pubkey cache syncPubkeys
([#537](#537))
([542779f](542779f))
* **bindings:** aggregate cached public keys by validator index
([#397](#397))
([2f90603](2f90603))
* **bindings:** align `BeaconStateView` with `IBeaconStateView`
([#347](#347))
([b8ec273](b8ec273))
* **bindings:** configurable pubkey cache growth step
([#481](#481))
([133ef24](133ef24))
* **bindings:** expose more APIs for STF
([#444](#444))
([7fe2609](7fe2609))
* **bls:** add small MSM for npoints &lt; 32
([#393](#393))
([b430638](b430638))
* **blst:** use external buffers for blst operations
([#358](#358))
([78e4678](78e4678))
* **ci:** conditionally publish bindings with tag
([#355](#355))
([ea77919](ea77919))
* **clock:** add clock module for slot/epoch timing
([#354](#354))
([385b077](385b077))
* **fork_choice:** add Prometheus metrics module
([#309](#309))
([cbc9d8d](cbc9d8d))
* **forkchoice:** implement the forkchoice module
([#246](#246))
([7c62a9b](7c62a9b))
* getSyncCommitteesWitness
([#367](#367))
([ef77649](ef77649))
* implement `loadState` API and binding
([#165](#165))
([f903519](f903519)),
closes [#159](#159)
* **metrics:** metrics bindings
([#455](#455))
([dd41999](dd41999))
* migrate blst,pubkeys to use zapi js dsl
([#331](#331))
([fcd26ca](fcd26ca))
* **pubkeys:** add getPubkeyBytes binding
([#555](#555))
([4ca51cf](4ca51cf))
* publish ARM64 musl bindings
([#482](#482))
([ac764c9](ac764c9))
* **shuffle:** add swap-or-not shuffling module and binding
([#559](#559))
([c2db37c](c2db37c))
* split nextValue fn
([#464](#464))
([b47faeb](b47faeb))
* support getLatestWeakSubjectivityCheckpointEpoch
([#366](#366))
([dcf3883](dcf3883))
* update fulu deposit processing
([#442](#442))
([064335c](064335c))


### Bug Fixes

* avoid set ([#484](#484))
([2e25d97](2e25d97))
* better generation of rand scalar
([#388](#388))
([74dce77](74dce77))
* **bindings:** accept `dontTransferCache` in processSlots for backward
compatibility
([#460](#460))
([65df5af](65df5af))
* **bindings:** check signature infinity by default
([#509](#509))
([2f5f281](2f5f281))
* **bindings:** clean up failed async BLS work
([#527](#527))
([1111b00](1111b00))
* **bindings:** free metrics writer on scrape failure
([#529](#529))
([4c8d94a](4c8d94a))
* **bindings:** harden random aggregate scalars
([#528](#528))
([8e89a63](8e89a63))
* **bindings:** log level for missing fields
([#435](#435))
([08faf41](08faf41))
* **bindings:** misordering of print for cpu count
([#381](#381))
([752a972](752a972))
* **bindings:** populate epoch participation for test fixtures
([#436](#436))
([8dbdd2e](8dbdd2e))
* **bindings:** refcount Pool to fix teardown panic
([#352](#352))
([23b2f68](23b2f68))
* **bindings:** roll back partial N-API initialization
([#491](#491))
([31c5ebb](31c5ebb))
* **bindings:** size BLS thread pool by cgroup-aware CPU count
([#386](#386))
([3ae9522](3ae9522))
* **bindings:** validate class types before unwrap
([#514](#514))
([2fd2ad5](2fd2ad5))
* **bindings:** validate secret key hex length
([#517](#517))
([136e415](136e415))
* **bls:** align PublicKey.uncompress validation with
Signature.uncompress
([#508](#508))
([5a8dbe9](5a8dbe9))
* **bls:** bound randomized aggregation inputs
([#548](#548))
([779d0bf](779d0bf)),
closes [#542](#542)
* **bls:** clean up partial thread pool initialization
([#490](#490))
([d55e598](d55e598))
* **bls:** convert pippenger scratch bytes to element counts
([#513](#513))
([a12ca92](a12ca92))
* **bls:** enforce 32-byte signing roots
([#545](#545))
([72fd308](72fd308))
* **bls:** make batch cardinality structural
([#547](#547))
([a06d8b2](a06d8b2))
* **bls:** preserve aggregate outputs on failure
([#521](#521))
([e0b6dd1](e0b6dd1))
* **bls:** reject empty keygen salts
([#524](#524))
([d2a9c86](d2a9c86))
* **bls:** reject unknown BLST error codes
([#525](#525))
([9e4a6ad](9e4a6ad))
* **bls:** size pairing buffers for 32-bit targets
([#531](#531))
([dc64a27](dc64a27))
* **blst:** default signature infinity check to true if not provided
([#387](#387))
([021cdcb](021cdcb))
* **build:** remove `zig-out` from `files`
([#360](#360))
([c52af09](c52af09))
* **ci:** fix caching spec test version
([#439](#439))
([96885a1](96885a1))
* dangling state pointer in loadOtherState
([#450](#450))
([81cbd5f](81cbd5f))
* **epoch_cache:** compute missing `next_proposers`
([#447](#447))
([0088a29](0088a29))
* **epoch_cache:** populate decision roots in afterProcessEpoch
([#453](#453))
([4b70a5e](4b70a5e))
* export asyncAggregateWithRandomness through napi binding
([#371](#371))
([1d04c2b](1d04c2b))
* harden memory safety across PMT, SSZ tree views, and state transition
([#377](#377))
([d6f5897](d6f5897))
* improve atomic ordering in ThreadPool and NAPI init
([#310](#310))
([4b0a1cc](4b0a1cc))
* interface compatbility with NativeBeaconStateView
([#445](#445))
([89e13d1](89e13d1))
* missing deinits in loadOtherState
([#459](#459))
([094d278](094d278))
* missing state commits
([#454](#454))
([a432b55](a432b55))
* no-op when syncPubkeys run on a pk cache with shrinking validator set
([#432](#432))
([ed05a99](ed05a99))
* param order in BeaconBlockBody
([#348](#348))
([d8b9c06](d8b9c06))
* pendingConsolidations bindings
([#449](#449))
([b9c497e](b9c497e))
* **pmt,ssz:** harden chunked-leaf and zero-copy tree-view memory safety
([#400](#400))
([de50c53](de50c53))
* populate cache balances during rewards/penalties processing
([#474](#474))
([5bf23dc](5bf23dc))
* re-expose sizes
([#369](#369))
([64b81f3](64b81f3))
* remove `slashValidator` gating on active status
([#448](#448))
([d319a0d](d319a0d))
* **ssz:** drop redundant default-init pass in fixed-list decode
([#468](#468))
([0c757be](0c757be))
* **ssz:** publish child cache entries after lookup
([#565](#565))
([21e78c9](21e78c9))
* state transition binding exports
([#456](#456))
([895982c](895982c))
* **state-transition:** group-check signature sets
([#515](#515))
([42774e9](42774e9)),
closes [#502](#502)
* **state-transition:** isolate epoch step cache mutations
([#535](#535))
([a83741a](a83741a))
* **state-transition:** repair Pool.init call broken by
[#346](https://github.com/ChainSafe/lodestar-z/issues/346)×[#367](https://github.com/ChainSafe/lodestar-z/issues/367)
merge skew ([#394](#394))
([b42944f](b42944f))
* various fixes around config
([#433](#433))
([c4f082c](c4f082c))


### Performance Improvements

* **bindings:** drop TS BLS comparison benches and report benchmarks on
PRs ([#552](#552))
([c909c6f](c909c6f))
* **bls:** add cache-aware signature verifier
([#562](#562))
([063857e](063857e))
* **bls:** bypass worker queue for small batches
([#553](#553))
([3f8a6df](3f8a6df))
* **epoch:** replace AutoHashMap with array lookup in reward/penalty
caches ([#286](#286))
([e4e181b](e4e181b)),
closes [#243](#243)
* **pmt:** chunked-leaf packing for basic lists and container_struct
([#346](#346))
([ba156c4](ba156c4))


### Code Refactoring

* allocate `AsyncAggRandData` in one obj
([#384](#384))
([459750f](459750f))
* **bindings/pubkeys:** simplify allocation strategy for aggregate
([#518](#518))
([b82750f](b82750f))
* **bindings:** rename blst Lifecycle to State
([#516](#516))
([0a9c179](0a9c179))
* **bindings:** use zapi js.io() instead of local io module
([#469](#469))
([2b34cc0](2b34cc0))
* **bindings:** wake only required number of workers
([#383](#383))
([1db57f1](1db57f1))
* **bls:** allocations around VMAS
([#395](#395))
([dfda58c](dfda58c))
* **bls:** clean up bls
([#398](#398))
([e0f3b9b](e0f3b9b))
* **bls:** remove need for tracking results for
verifyMultipleAggregateSignatures
([#389](#389))
([6fe5c3f](6fe5c3f))
* **bls:** remove single-threaded fallback
([#390](#390))
([e057713](e057713))
* **clock:** single public Clock; internalize SlotClock
([#463](#463))
([fbab1fa](fbab1fa))
* make XXXDecisionRoot fns return `js.String`
([#342](#342))
([aef4420](aef4420))
* move shuffle into swap_or_not_shuffle module
([#558](#558))
([e56efb2](e56efb2))
* **pubkeys:** centralize the process-wide cache
([#522](#522))
([dc9669d](dc9669d))


### Miscellaneous Chores

* avoid slow tests in AGENTS.md
([#546](#546))
([c60f2a9](c60f2a9))
* bump zapi to include musl build
([#485](#485))
([0b488cc](0b488cc))
* **ci:** pin github actions with sha hashes
([#507](#507))
([167b8f5](167b8f5))
* deprecate unused blst APIs
([#575](#575))
([7b547fa](7b547fa))
* **deps:** bump zapi v2.1.0 -&gt; v2.2.0
([#376](#376))
([0c240d8](0c240d8))
* **deps:** bump zbuild
([#403](#403))
([e2545de](e2545de))
* **deps:** compile blst with ReleaseFast
([#391](#391))
([753a896](753a896))
* **deps:** update zapi to 3.1.0
([#483](#483))
([f3e5827](f3e5827))
* **deps:** use zapi v2.1.0
([#372](#372))
([88f403a](88f403a))
* disable gemini auto code review
([#382](#382))
([63e42a4](63e42a4)),
closes [#380](#380)
* **docs:** add comments section in AGENTS.md
([#566](#566))
([0c09750](0c09750))
* move state clones out of benchmark run functions
([#324](#324))
([e4035de](e4035de))
* prepare 1.0.0 release
([#576](#576))
([20b657b](20b657b))
* release v0.1.2-rc.3
([#370](#370))
([e4fc551](e4fc551))
* **release:** 0.1.2-rc.2
([#365](#365))
([7046128](7046128))
* **release:** v0.1.2-rc.10
([#477](#477))
([9a4fad5](9a4fad5))
* **release:** v0.1.2-rc.4
([#373](#373))
([09468f1](09468f1))
* **release:** v0.1.2-rc.5
([#374](#374))
([f344efa](f344efa))
* **release:** v0.1.2-rc.6
([#375](#375))
([bdf5b67](bdf5b67))
* **release:** v0.1.2-rc.8
([#401](#401))
([06f91c2](06f91c2))
* **release:** v0.1.2-rc.9
([#404](#404))
([6024800](6024800))
* remove merge transition code
([#359](#359))
([09b175d](09b175d))
* remove stale epoch cache TODOs
([#534](#534))
([27a547a](27a547a))
* rename era shortHistoricalRoot to shortEraRoot
([#473](#473))
([c75a4d3](c75a4d3))
* **scripts:** build bindings with preset
([#434](#434))
([a1b5ef7](a1b5ef7))
* silence debug log when used in release builds
([#486](#486))
([c5377d7](c5377d7))
* support dev workflow
([#364](#364))
([fcb9a78](fcb9a78))
* update gloas types to align with the latest specs
([#431](#431))
([1f065b5](1f065b5))
* update spec test version to v1.7.0-alpha.11
([#451](#451))
([5875660](5875660))
* update spec-test-version: v1.6.0-beta.2 -&gt; v1.7.0-alpha.10
([#441](#441))
([f932b1c](f932b1c))
* update zapi to 4.0.0
([#571](#571))
([de8e3fd](de8e3fd))


### Documentation

* document security threat model
([#557](#557))
([e678b87](e678b87))
* more comprehensive AGENTS.md
([#520](#520))
([c74b386](c74b386))
* **pkix:** document load provenance requirement
([#556](#556))
([37e0aa2](37e0aa2))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants