-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multihomed transport (server) addrs 🕶️ #367
base: asyncio_debugger_support
Are you sure you want to change the base?
Commits on Sep 27, 2023
-
Mk
gather_contexts()
support@acm
s yieldingNone
We were using a `all(<yielded values>)` condition which obviously won't work if the batched managers yield any non-truthy value. So instead see the `unwrapped: dict` with the `id(mngrs)` and only unblock once all values have been filled in to be something that is not that value.
Configuration menu - View commit details
-
Copy full SHA for ee151b0 - Browse repository at this point
Copy the full SHA ee151b0View commit details -
Init-support for "multi homed" transports
Since we'd like to eventually allow a diverse set of transport (protocol) methods and stacks, and a multi-peer discovery system for distributed actor-tree applications, this reworks all runtime internals to support multi-homing for any given tree on a logical host. In other words any actor can now bind its transport server (currently only unsecured TCP + `msgspec`) to more then one address available in its (linux) network namespace. Further, registry actors (now dubbed "registars" instead of "arbiters") can also similarly bind to multiple network addresses and provide discovery services to remote actors via multiple addresses which can now be provided at runtime startup. Deats: - adjust `._runtime` internals to use a `list[tuple[str, int]]` (and thus pluralized) socket address sequence where applicable for transport server socket binds, now exposed via `Actor.accept_addrs`: - `Actor.__init__()` now takes a `registry_addrs: list`. - `Actor.is_arbiter` -> `.is_registrar`. - `._arb_addr` -> `._reg_addrs: list[tuple]`. - always reg and de-reg from all registrars in `async_main()`. - only set the global runtime var `'_root_mailbox'` to the loopback address since normally all in-tree processes should have access to it, right? - `._serve_forever()` task now takes `listen_sockaddrs: list[tuple]` - make `open_root_actor()` take a `registry_addrs: list[tuple[str, int]]` and defaults when not passed. - change `ActorNursery.start_..()` methods take `bind_addrs: list` and pass down through the spawning layer(s) via the parent-seed-msg. - generalize all `._discovery()` APIs to accept `registry_addrs`-like inputs and move all relevant subsystems to adopt the "registry" style naming instead of "arbiter": - make `find_actor()` support batched concurrent portal queries over all provided input addresses using `.trionics.gather_contexts()` Bo - syntax: move to using `async with <tuples>` 3.9+ style chained @acms. - a general modernization of the code to a python 3.9+ style. - start deprecation and change to "registry" naming / semantics: - `._discovery.get_arbiter()` -> `.get_registry()`
Configuration menu - View commit details
-
Copy full SHA for 3d0e955 - Browse repository at this point
Copy the full SHA 3d0e955View commit details
Commits on Sep 28, 2023
-
Kick off
.devx
subpkg for our dev tools B)Where `.devx` is "developer experience", a hopefully broad enough subpkg name for all the slick stuff planned to augment working on the actor runtime 💥 Move the `._debug` module into the new subpkg and adjust rest of core code base to reflect import path change. Also add a new `.devx._debug.open_crash_handler()` manager for wrapping any sync code outside a `trio.run()` which is handy for eventual CLI addons for popular frameworks like `click`/`typer`.
Configuration menu - View commit details
-
Copy full SHA for fa9a9cf - Browse repository at this point
Copy the full SHA fa9a9cfView commit details -
Start
.devx.cli
extensions for pop CLI frameworksStarting of with just a `typer` (and thus transitively `click`) `typer.Typer.callback` hook which allows passthrough of the `--ll <loglevel: str>` and `--pdb <debug_mode: bool>` flags for use when building CLIs that use the runtime Bo Still needs lotsa refinement and obviously better docs but, the doc string for `load_runtime_vars()` shows how to use the underlying `.devx._debug.open_crash_handler()` via a wrapper that can be passed the `--pdb` flag and then enable debug mode throughout the entire actor system.
Configuration menu - View commit details
-
Copy full SHA for 7bed470 - Browse repository at this point
Copy the full SHA 7bed470View commit details
Commits on Sep 29, 2023
-
Add libp2p style "multi-address" parser from
piker
Details are in the module docs; this is a first draft with lotsa room for refinement and extension.
Configuration menu - View commit details
-
Copy full SHA for de89e3a - Browse repository at this point
Copy the full SHA de89e3aView commit details -
Configuration menu - View commit details
-
Copy full SHA for 86da79a - Browse repository at this point
Copy the full SHA 86da79aView commit details
Commits on Oct 2, 2023
-
Configuration menu - View commit details
-
Copy full SHA for e94f126 - Browse repository at this point
Copy the full SHA e94f126View commit details
Commits on Oct 3, 2023
-
Add post-mortem catch around failed transport addr binds to aid with …
…runtime debugging
Configuration menu - View commit details
-
Copy full SHA for 4314a59 - Browse repository at this point
Copy the full SHA 4314a59View commit details
Commits on Oct 6, 2023
-
Start inter-peer cancellation test mod
Move over relevant test from the "context semantics" test module which was already verifying peer-caused-`ContextCancelled.canceller: tuple` error info and propagation during an inter-peer cancellation scenario. Also begin a more general set of inter-peer cancellation tests starting with the simplest case where when a peer is cancelled the parent should NOT get an "muted" `trio.Cancelled` and instead a `tractor.ContextCancelled` with a `.canceller: tuple` which points to the sibling actor which requested the peer cancel.
Configuration menu - View commit details
-
Copy full SHA for 78c0d2b - Browse repository at this point
Copy the full SHA 78c0d2bView commit details -
Add shielding support to
.pause()
Implement it like you'd expect using simply a wrapping `trio.CancelScope` which is itself shielded by the input `shield: bool` B) There's seemingly still some issues with the frame selection when the REPL engages and not sure how to resolve it yet but at least this does indeed work for practical purposes. Still needs a test obviously!
Configuration menu - View commit details
-
Copy full SHA for 18a1634 - Browse repository at this point
Copy the full SHA 18a1634View commit details
Commits on Oct 7, 2023
-
Configuration menu - View commit details
-
Copy full SHA for d24a9e1 - Browse repository at this point
Copy the full SHA d24a9e1View commit details -
Configuration menu - View commit details
-
Copy full SHA for c4cd573 - Browse repository at this point
Copy the full SHA c4cd573View commit details -
Configuration menu - View commit details
-
Copy full SHA for a09b856 - Browse repository at this point
Copy the full SHA a09b856View commit details
Commits on Oct 8, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 919e462 - Browse repository at this point
Copy the full SHA 919e462View commit details
Commits on Oct 10, 2023
-
Always raise remote (cancelled) error if set
Previously we weren't raising a remote error if the local scope was cancelled during a call to `Context.result()` which is problematic if the caller WAS NOT the requester for said remote cancellation; in that case we still want a `ContextCancelled` raised with the `.canceller: str` set to the cancelling actor uid. Further fix a naming bug where the (seemingly older) `._remote_err` was being set to such an error instead of `._remote_error` XD
Configuration menu - View commit details
-
Copy full SHA for 575a24a - Browse repository at this point
Copy the full SHA 575a24aView commit details -
Comment all
.pause(shield=True)
attempts again, need to solve cance……l scope `.__exit__()` frame hiding issue..
Configuration menu - View commit details
-
Copy full SHA for 6d951c5 - Browse repository at this point
Copy the full SHA 6d951c5View commit details
Commits on Oct 16, 2023
-
Factor non-yield stream msg processing into helper
Since both `MsgStream.receive()` and `.receive_nowait()` need the same raising logic when a non-stream msg arrives (so that maybe an appropriate IPC translated error can be raised) move the `KeyError` handler code into a new `._streaming._raise_from_no_yield_msg()` func and call it from both methods to make the error-interface-raising symmetrical across both methods.
Configuration menu - View commit details
-
Copy full SHA for 2fdb8fc - Browse repository at this point
Copy the full SHA 2fdb8fcView commit details -
Configuration menu - View commit details
-
Copy full SHA for 07cec02 - Browse repository at this point
Copy the full SHA 07cec02View commit details -
Configuration menu - View commit details
-
Copy full SHA for ae326cb - Browse repository at this point
Copy the full SHA ae326cbView commit details -
Configuration menu - View commit details
-
Copy full SHA for ab2664d - Browse repository at this point
Copy the full SHA ab2664dView commit details -
._exceptions
: typing and error unpacking updatesBump type annotations to 3.10+ style throughout module as well as fill out doc strings a bit. Inside `unpack_error()` pop any `error_dict: dict` and, - return `None` early if not found, - versus pass directly as `**error_dict` to the error constructor instead of a double field read.
Configuration menu - View commit details
-
Copy full SHA for e4a6223 - Browse repository at this point
Copy the full SHA e4a6223View commit details
Commits on Oct 17, 2023
-
Drop
msg
kwarg fromContext.cancel()
Well first off, turns out it's never used and generally speaking doesn't seem to help much with "runtime hacking/debugging"; why would we need to "fabricate" a msg when `.cancel()` is called to self-cancel? Also (and since `._maybe_cancel_and_set_remote_error()` now takes an `error: BaseException` as input and thus expects error-msg unpacking prior to being called), we now manually set `Context._cancel_msg: dict` just prior to any remote error assignment - so any case where we would have fabbed a "cancel msg" near calling `.cancel()`, just do the manual assign. In this vein some other subtle changes: - obviously don't set `._cancel_msg` in `.cancel()` since it's no longer an input. - generally do walrus-style `error := unpack_error()` before applying and setting remote error-msg state. - always raise any `._remote_error` in `.result()` instead of returning the exception instance and check before AND after the underlying mem chan read. - add notes/todos around `raise self._remote_error from None` masking of (runtime) errors in `._maybe_raise_remote_err()` and use it inside `.result()` since we had the inverse duplicate logic there anyway.. Further, this adds and extends a ton of (internal) interface docs and details comments around the `Context` API including many subtleties pertaining to calling `._maybe_cancel_and_set_remote_error()`.
Configuration menu - View commit details
-
Copy full SHA for 534e5d1 - Browse repository at this point
Copy the full SHA 534e5d1View commit details -
Configuration menu - View commit details
-
Copy full SHA for 7eb31f3 - Browse repository at this point
Copy the full SHA 7eb31f3View commit details
Commits on Oct 18, 2023
-
Get mega-pedantic in
Portal.open_context()
Specifically in the `.__aexit__()` phase to ensure remote, runtime-internal, and locally raised error-during-cancelled-handling exceptions are NEVER masked by a local `ContextCancelled` or any exception group of `trio.Cancelled`s. Also adds a ton of details to doc strings including extreme detail surrounding the `ContextCancelled` raising cases and their processing inside `.open_context()`'s exception handler blocks. Details, details: - internal rename `err`/`_err` stuff to just be `scope_err` since it's effectively the error bubbled up from the context's surrounding (and cross-actor) "scope". - always shield `._recv_chan.aclose()` to avoid any `Cancelled` from masking the `scope_err` with a runtime related `trio.Cancelled`. - explicitly catch the specific set of `scope_err: BaseException` that we can reasonably expect to handle instead of the catch-all parent type including exception groups, cancels and KBIs.
Configuration menu - View commit details
-
Copy full SHA for 63b1488 - Browse repository at this point
Copy the full SHA 63b1488View commit details -
Configuration menu - View commit details
-
Copy full SHA for 43b659d - Browse repository at this point
Copy the full SHA 43b659dView commit details -
Configuration menu - View commit details
-
Copy full SHA for 87c1113 - Browse repository at this point
Copy the full SHA 87c1113View commit details -
Add a first serious inter-peer remote cancel suite
Tests that appropriate `Context` exit state, the relay of a `ContextCancelled` error and its `.canceller: tuple[str, str]` value are set when an inter-peer cancellation happens via an "out of band" request method (in this case using `Portal.cancel_actor()` and that cancellation is propagated "horizontally" to other peers. Verify that any such cancellation scenario which also experiences an "error during `ContextCancelled` handling" DOES NOT result in that further error being suppressed and that the user's exception bubbles out of the `Context.open_context()` block(s) appropriately! Likely more tests to come as well as some factoring of the teardown state checks where possible. Pertains to serious testing the major work landing in #357
Configuration menu - View commit details
-
Copy full SHA for ca3f7a1 - Browse repository at this point
Copy the full SHA ca3f7a1View commit details -
Configuration menu - View commit details
-
Copy full SHA for fcc8cee - Browse repository at this point
Copy the full SHA fcc8ceeView commit details -
Configuration menu - View commit details
-
Copy full SHA for 215fec1 - Browse repository at this point
Copy the full SHA 215fec1View commit details -
Configuration menu - View commit details
-
Copy full SHA for 0c74b04 - Browse repository at this point
Copy the full SHA 0c74b04View commit details -
Configuration menu - View commit details
-
Copy full SHA for 190845c - Browse repository at this point
Copy the full SHA 190845cView commit details -
Rename fixture
arb_addr
->reg_addr
and set the session value glo……bally as `._root._default_lo_addrs`
Configuration menu - View commit details
-
Copy full SHA for 1e689ee - Browse repository at this point
Copy the full SHA 1e689eeView commit details -
Configuration menu - View commit details
-
Copy full SHA for 6b1ceee - Browse repository at this point
Copy the full SHA 6b1ceeeView commit details -
Configuration menu - View commit details
-
Copy full SHA for 0e94572 - Browse repository at this point
Copy the full SHA 0e94572View commit details -
Configuration menu - View commit details
-
Copy full SHA for 022bf8c - Browse repository at this point
Copy the full SHA 022bf8cView commit details -
Configuration menu - View commit details
-
Copy full SHA for 2e81ccf - Browse repository at this point
Copy the full SHA 2e81ccfView commit details -
Configuration menu - View commit details
-
Copy full SHA for 42d621b - Browse repository at this point
Copy the full SHA 42d621bView commit details
Commits on Oct 19, 2023
-
Get remaining suites passing..
..by ensuring `reg_addr` fixture value passthrough to subactor eps
Configuration menu - View commit details
-
Copy full SHA for a3ed30e - Browse repository at this point
Copy the full SHA a3ed30eView commit details -
Expose per-actor registry addrs via
.reg_addrs
Since it's handy to be able to debug the *writing* of this instance var (particularly when checking state passed down to a child in `Actor._from_parent()`), rename and wrap the underlying `Actor._reg_addrs` as a settable `@property` and add validation to the `.setter` for sanity - actor discovery is a critical functionality. Other tweaks: - fix `.cancel_soon()` to pass expected argument.. - update internal runtime error message to be simpler and link to GH issues. - use new `Actor.reg_addrs` throughout core.
Configuration menu - View commit details
-
Copy full SHA for 1d6f555 - Browse repository at this point
Copy the full SHA 1d6f555View commit details -
Configuration menu - View commit details
-
Copy full SHA for 9da3b63 - Browse repository at this point
Copy the full SHA 9da3b63View commit details -
Configuration menu - View commit details
-
Copy full SHA for 2f0bed3 - Browse repository at this point
Copy the full SHA 2f0bed3View commit details
Commits on Oct 23, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 0518b3a - Browse repository at this point
Copy the full SHA 0518b3aView commit details -
Configuration menu - View commit details
-
Copy full SHA for 5a94e8f - Browse repository at this point
Copy the full SHA 5a94e8fView commit details -
Be mega-pedantic with
ContextCancelled
semanticsAs part of extremely detailed inter-peer-actor testing, add much more granular `Context` cancellation state tracking via the following (new) fields: - `.canceller: tuple[str, str]` the uuid of the actor responsible for the cancellation condition - always set by `Context._maybe_cancel_and_set_remote_error()` and replaces `._cancelled_remote` and `.cancel_called_remote`. If set, this value should normally always match a value from some `ContextCancelled` raised or caught by one side of the context. - `._local_error` which is always set to the locally raised (and caller or callee task's scope-internal) error which caused any eventual cancellation/error condition and thus any closure of the context's per-task-side-`trio.Nursery`. - `.cancelled_caught: bool` is now always `True` whenever the local task catches (or "silently absorbs") a `ContextCancelled` (a `ctxc`) that indeed originated from one of the context's linked tasks or any other context which raised its own `ctxc` in the current `.open_context()` scope. => whenever there is a case that no `ContextCancelled` was raised **in** the `.open_context().__aexit__()` (eg. `ctx.result()` called after a call `ctx.cancel()`), we still consider the context's as having "caught a cancellation" since the `ctxc` was indeed silently handled by the cancel requester; all other error cases are already represented by mirroring the state of the `._scope: trio.CancelScope` => IOW there should be **no case** where an error is **not raised** in the context's scope and `.cancelled_caught: bool == False`, i.e. no case where `._scope.cancelled_caught == False and ._local_error is not None`! - always raise any `ctxc` from `.open_stream()` if `._cancel_called == True` - if the cancellation request has not already resulted in a `._remote_error: ContextCancelled` we raise a `RuntimeError` to indicate improper usage to the guilty side's task code. - make `._maybe_raise_remote_err()` a sync func and don't raise any `ctxc` which is matched against a `.canceller` determined to be the current actor, aka a "self cancel", and always set the `._local_error` to any such `ctxc`. - `.side: str` taken from inside `.cancel()` and unused as of now since it might be better re-written as a similar `.is_opener() -> bool`? - drop unused `._started_received: bool`.. - TONS and TONS of detailed comments/docs to attempt to explain all the possible cancellation/exit cases and how they should exhibit as either silent closes or raises from the `Context` API! Adjust the `._runtime._invoke()` code to match: - use `ctx._maybe_raise_remote_err()` in `._invoke()`. - adjust to new `.canceller` property. - more type hints. - better `log.cancel()` msging around self-cancels vs. peer-cancels. - always set the `._local_error: BaseException` for the "callee" task just like `Portal.open_context()` now will do B) Prior we were raising any `Context._remote_error` directly and doing (more or less) the same `ContextCancelled` "absorbing" logic (well kinda) in block; instead delegate to the method
Configuration menu - View commit details
-
Copy full SHA for 131674e - Browse repository at this point
Copy the full SHA 131674eView commit details -
Be ultra-correct in
Portal.open_context()
This took way too long to get right but hopefully will give us grok-able and correct context exit semantics going forward B) The main fixes were: - always shielding the `MsgStream.aclose()` call on teardown to avoid bubbling a `Cancelled`. - properly absorbing any `ContextCancelled` in cases due to "self cancellation" using the new `Context.canceller` in the logic. - capturing any error raised by the `Context.result()` call in the "normal exit, result received" case and setting it as the `Context._local_error` so that self-cancels can be easily measured via `Context.cancelled_caught` in same way as remote-error caused cancellations. - extremely detailed comments around all of the cancellation-error cases to avoid ever getting confused about the control flow in the future XD
Configuration menu - View commit details
-
Copy full SHA for df31047 - Browse repository at this point
Copy the full SHA df31047View commit details -
Configuration menu - View commit details
-
Copy full SHA for f4e6346 - Browse repository at this point
Copy the full SHA f4e6346View commit details -
Configuration menu - View commit details
-
Copy full SHA for b77d123 - Browse repository at this point
Copy the full SHA b77d123View commit details -
Adjust test details where
Context.cancel()
is calledWe can now make asserts on `.cancelled_caught` and `_remote_error` vs. `_local_error`. Expect a runtime error when `Context.open_stream()` is called AFTER `.cancel()` and the remote `ContextCancelled` hasn't arrived (yet). Adjust to `'itself'` string in self-cancel case.
Configuration menu - View commit details
-
Copy full SHA for ecb525a - Browse repository at this point
Copy the full SHA ecb525aView commit details -
Get inter-peer suite passing with all
Context
state checks!Definitely needs some cleaning and refinement but this gets us to stage 1 of being pretty frickin correct i'd say 💃
Configuration menu - View commit details
-
Copy full SHA for ef0cfc4 - Browse repository at this point
Copy the full SHA ef0cfc4View commit details
Commits on Oct 25, 2023
-
Tons of interpeer test cleanup
Drop all the nested `@acm` blocks and defunct comments from initial validations. Add some todos for cases that are still unclear such as whether the caller / streamer should have `.cancelled_caught == True` in it's teardown.
Configuration menu - View commit details
-
Copy full SHA for d651f3d - Browse repository at this point
Copy the full SHA d651f3dView commit details
Commits on Nov 6, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 227c9ea - Browse repository at this point
Copy the full SHA 227c9eaView commit details -
Configuration menu - View commit details
-
Copy full SHA for 48accbd - Browse repository at this point
Copy the full SHA 48accbdView commit details
Commits on Nov 7, 2023
-
Add
open_root_actor(ensure_registry: bool)
Allows forcing the opened actor to either obtain the passed registry addrs or raise a runtime error.
Configuration menu - View commit details
-
Copy full SHA for 87cd725 - Browse repository at this point
Copy the full SHA 87cd725View commit details
Commits on Dec 11, 2023
-
Configuration menu - View commit details
-
Copy full SHA for 3f15923 - Browse repository at this point
Copy the full SHA 3f15923View commit details
Commits on Dec 12, 2023
-
Configuration menu - View commit details
-
Copy full SHA for f415fc4 - Browse repository at this point
Copy the full SHA f415fc4View commit details
Commits on Jan 2, 2024
-
Guarding for IPC failures in
._runtime._invoke()
Took me longer then i wanted to figure out the source of a failed-response to a remote-cancellation (in this case in `modden` where a client was cancelling a workspace layer.. but disconnects before receiving the ack msg) that was triggering an IPC error when sending the error msg for the cancellation of a `Actor._cancel_task()`, but since this (non-rpc) `._invoke()` task was trying to send to a now disconnected canceller it was resulting in a `BrokenPipeError` (or similar) error. Now, we except for such IPC errors and only raise them when, 1. the transport `Channel` is for sure up (bc ow what's the point of trying to send an error on the thing that caused it..) 2. it's definitely for handling an RPC task Similarly if the entire main invoke `try:` excepts, - we only hide the call-stack frame from the debugger (with `__tracebackhide__: bool`) if it's an RPC task that has a connected channel since we always want to see the frame when debugging internal task or IPC failures. - we don't bother trying to send errors to the context caller (actor) when it's a non-RPC request since failures on actor-runtime-internal tasks shouldn't really ever be reported remotely, only maybe raised locally. Also some other tidying, - this properly corrects for the self-cancel case where an RPC context is cancelled due to a local (runtime) task calling a method like `Actor.cancel_soon()`. We now set our own `.uid` as the `ContextCancelled.canceller` value so that other-end tasks know that the cancellation was due to a self-cancellation by the actor itself. We still need to properly test for this though! - add a more detailed module doc-str. - more explicit imports for `trio` core types throughout.
Configuration menu - View commit details
-
Copy full SHA for 250275d - Browse repository at this point
Copy the full SHA 250275dView commit details -
Configuration menu - View commit details
-
Copy full SHA for bea31f6 - Browse repository at this point
Copy the full SHA bea31f6View commit details -
Configuration menu - View commit details
-
Copy full SHA for 8143848 - Browse repository at this point
Copy the full SHA 8143848View commit details -
StackLevelAdapter._log(stacklevel: int)
for custom levels..Apparently (and i don't know if this was always broken [i feel like no?] or is a recent change to stdlib's `logging` stuff) we need increment the `stacklevel` input by one for our custom level methods now? Without this you're going to see the path to the method's-callstack-frame on every emission instead of to the caller's. I first noticed this when debugging the workspace layer spawning in `modden.bigd` and then verified it in other depended projects.. I guess we should add some tests for this as well XD
Configuration menu - View commit details
-
Copy full SHA for 0002418 - Browse repository at this point
Copy the full SHA 0002418View commit details -
Configuration menu - View commit details
-
Copy full SHA for ce7b8a5 - Browse repository at this point
Copy the full SHA ce7b8a5View commit details -
Configuration menu - View commit details
-
Copy full SHA for fdf3a1b - Browse repository at this point
Copy the full SHA fdf3a1bView commit details -
Configuration menu - View commit details
-
Copy full SHA for 0bcdea2 - Browse repository at this point
Copy the full SHA 0bcdea2View commit details -
Move missing-key-in-msg raiser to
._exceptions
Since we use basically the exact same set of logic in `Portal.open_context()` when expecting the first `'started'` msg factor and generalize `._streaming._raise_from_no_yield_msg()` into a new `._exceptions._raise_from_no_key_in_msg()` (as per the lingering todo) which obvi requires a more generalized / optional signature including a caller specific `log` obj. Obvi call the new func from all the other modules X)
Configuration menu - View commit details
-
Copy full SHA for 734bc09 - Browse repository at this point
Copy the full SHA 734bc09View commit details -
Configuration menu - View commit details
-
Copy full SHA for 0294455 - Browse repository at this point
Copy the full SHA 0294455View commit details
Commits on Jan 4, 2024
-
Configuration menu - View commit details
-
Copy full SHA for 28ea8e7 - Browse repository at this point
Copy the full SHA 28ea8e7View commit details