-
Notifications
You must be signed in to change notification settings - Fork 7
Feature: EOD time management module - di.eodtime #94
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
Changes from all commits
65516d1
3538ed6
79b5400
d5874bd
bb637de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| # di.eodtime | ||
|
|
||
| End-of-day time management for TorQ-based tickerplant processes. Resolves the current trading date in a configurable roll timezone, calculates the next EOD roll timestamp in UTC, and computes a daily UTC offset used to timestamp incoming data. | ||
|
|
||
| --- | ||
|
|
||
| ## Dependencies | ||
|
|
||
| | Dependency | Key | Required | Description | | ||
| |---|---|---|---| | ||
| | logger | `log` | yes | `info`, `warn`, `error` — each binary `{[c;m]}` where `c` is a symbol context and `m` is a string | | ||
|
|
||
| **Hard dependency:** `di.tz` — loaded automatically when the module is imported. | ||
|
|
||
| The `log` dependency must be passed to `init` inside the `configs` dict. The module | ||
| throws immediately if it is absent or missing any of the three required keys. | ||
|
|
||
| A `kx.log` instance can be passed directly — the module normalises monadic functions | ||
| to the binary `{[c;m]}` contract automatically: | ||
|
|
||
| ```q | ||
| kxlog:use`kx.log | ||
| eodtime:use`di.eodtime | ||
| eodtime.init[`log`rolltimezone!(kxlog.createLog[];`$"Europe/London")] | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Initialisation | ||
|
|
||
| `init[configs]` takes a single dictionary combining the `log` dependency with | ||
| any configuration overrides. | ||
|
|
||
| | Key | Required | Description | | ||
| |---|---|---| | ||
| | `log` | yes | Binary log dep — `info`, `warn`, `error` functions each `{[c;m]}` | | ||
| | `rolltimezone` | no | Timezone used for EOD roll scheduling. Default: `` `$"GMT" `` | | ||
| | `datatimezone` | no | Timezone used for stamping incoming data. Default: `` `$"GMT" `` | | ||
| | `rolltimeoffset` | no | Offset from midnight for the EOD roll (e.g. `0D17:00:00.000` for a 5pm roll). Default: `0D` | | ||
|
|
||
| Passing only the required `log` key loads the module with defaults that match TorQ's original `eodtime.q` behaviour: | ||
|
|
||
| ```q | ||
| eodtime.init[enlist[`log]!enlist logdep] | ||
| ``` | ||
|
|
||
| `init` must be called before any other function is used. It computes the initial values of `d`, `nextroll`, and `dailyadj`. Calling getters before `init` returns uninitialised defaults (`0Nd`, `0Wp`, `0D`) which will silently produce wrong results in downstream processes. | ||
|
|
||
| Timezone values should be standard timezone identifiers in the format `"Region/City"` (e.g. `"Europe/London"`, `"America/New_York"`). The values `"GMT"`, `"UTC"` and `"Etc/GMT"` are handled as zero-offset shortcuts directly, without a timezone lookup. `"GMT"` is not recognised by `di.tz` but is the TorQ default, so this ensures the module works out of the box with existing TorQ products. Note: `"Etc/UTC"` is a valid argument in `di.tz`. | ||
|
|
||
| --- | ||
|
|
||
| ## Exported functions | ||
|
|
||
| ### `init` | ||
| Initialises the module. Validates the log dependency, applies config, and computes initial values of `d`, `nextroll`, and `dailyadj`. | ||
| ```q | ||
| eodtime.init[`log`rolltimezone`datatimezone`rolltimeoffset!(logdep;`$"Europe/London";`$"GMT";0D)] | ||
| / or with defaults only: | ||
| eodtime.init[enlist[`log]!enlist logdep] | ||
| ``` | ||
|
|
||
| ### `getd` | ||
| Returns the current trading date in the roll timezone. | ||
| ```q | ||
| eodtime.getd[] | ||
| / 2025.06.01 | ||
| ``` | ||
|
|
||
| ### `getnextroll` | ||
| Returns the UTC timestamp of the next scheduled EOD roll. | ||
| ```q | ||
| eodtime.getnextroll[] | ||
| / 2025.06.02D00:00:00.000000000 | ||
| ``` | ||
|
|
||
| ### `getdailyadj` | ||
| Returns the **cached** UTC offset for the data timezone - the value stored at the last `init` or `setdailyadj` call. Used by upstream processes to stamp incoming data: | ||
| ```q | ||
| .z.p + eodtime.getdailyadj[] | ||
| / adds the stored offset to the current UTC time | ||
| ``` | ||
|
|
||
| ### `getdailyadjustment` | ||
| **Recomputes** the UTC offset for the data timezone at the current time. Call this after an EOD roll to get a fresh offset - important when the data timezone observes daylight saving time, as the offset changes at the transition. | ||
| ```q | ||
| eodtime.getdailyadjustment[] | ||
| / 0D01:00:00.000000000 | ||
| ``` | ||
|
|
||
| ### `getroll` | ||
| Computes the UTC timestamp of the next EOD roll after UTC timestamp `p`. Returns today's roll time if the roll has not yet passed; returns tomorrow's if it has. | ||
| ```q | ||
| eodtime.getroll[.z.p] | ||
| / 2025.06.02D00:00:00.000000000 | ||
| ``` | ||
|
|
||
| ### `setnextroll` | ||
| Updates the stored next roll timestamp. Called by the tickerplant and segmented tickerplant after completing an EOD roll. | ||
| ```q | ||
| eodtime.setnextroll eodtime.getroll[.z.p] | ||
| ``` | ||
|
|
||
| ### `setdailyadj` | ||
| Updates the stored daily adjustment offset. Called by the tickerplant after an EOD roll to refresh the offset for the new day. | ||
| ```q | ||
| eodtime.setdailyadj eodtime.getdailyadjustment[] | ||
| ``` | ||
|
|
||
| ### `setd` | ||
| Updates the stored trading date. Called by the segmented tickerplant to advance the date after an EOD roll. | ||
| ```q | ||
| eodtime.setd[1+eodtime.getd[]] | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Usage example | ||
|
|
||
| ```q | ||
| kxlog:use`kx.log | ||
|
|
||
| / load and initialise for a London-based system rolling at midnight | ||
| eodtime:use`di.eodtime | ||
| eodtime.init[`log`rolltimezone`datatimezone`rolltimeoffset!(kxlog.createLog[];`$"Europe/London";`$"GMT";0D)] | ||
|
|
||
| / check current state | ||
| eodtime.getd[] / today's trading date in London time | ||
| eodtime.getnextroll[] / next midnight UTC (23:00 UTC in summer) | ||
| eodtime.getdailyadj[] / current UTC offset for data timestamping | ||
|
|
||
| / simulate what a tickerplant does at EOD roll | ||
| eodtime.setnextroll eodtime.getroll[.z.p]; | ||
| eodtime.setdailyadj eodtime.getdailyadjustment[]; | ||
|
|
||
| / simulate what the segmented tickerplant does at EOD roll | ||
| eodtime.setd[1+eodtime.getd[]] | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## TorQ migration pattern | ||
|
|
||
| | TorQ pattern | Module equivalent | | ||
| |--------------------------------------------------------|------------------------------------------------------| | ||
| | `.eodtime.d` (read) | `eodtime.getd[]` | | ||
| | `.eodtime.nextroll` (read) | `eodtime.getnextroll[]` | | ||
| | `.eodtime.dailyadj` (read) | `eodtime.getdailyadj[]` | | ||
| | `.eodtime.getroll[p]` | `eodtime.getroll[p]` | | ||
| | `.eodtime.getdailyadjustment[]` | `eodtime.getdailyadjustment[]` | | ||
| | `.eodtime.nextroll:.eodtime.getroll[.z.p]` | `eodtime.setnextroll eodtime.getroll[.z.p]` | | ||
| | `.eodtime.dailyadj:.eodtime.getdailyadjustment[]` | `eodtime.setdailyadj eodtime.getdailyadjustment[]` | | ||
| | `.eodtime.d+:1` | `eodtime.setd[1+eodtime.getd[]]` | | ||
|
|
||
| --- | ||
|
|
||
| ## Notes | ||
|
|
||
| - `rolltimeoffset` adjusts the roll time from midnight e.g. `0D17:00:00.000` produces a 5pm local roll. | ||
| - `getdailyadj` returns the cached offset; `getdailyadjustment` recomputes it fresh. Always call `getdailyadjustment` after an EOD roll rather than relying on the cached value. | ||
| - `"GMT"`, `"UTC"` and `"Etc/GMT"` are not in the timezone database used by `di.tz` and are handled as zero-offset shortcuts directly in this module. `"Etc/UTC"` is valid and passed through to `di.tz` normally. All other timezone values are passed through to `di.tz`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| / end-of-day time management - date resolution, roll scheduling and data timestamp adjustment | ||
|
|
||
| / utc-equivalent timezone names - zero offset from utc so no timezone lookup required | ||
| utczones:`$("GMT";"UTC";"Etc/GMT"); | ||
|
|
||
| / ============================================================ | ||
| / module state and defaults | ||
| / ============================================================ | ||
|
|
||
| / roll timezone for eod scheduling - overwritten by init | ||
| rolltimezone:`$"GMT"; | ||
|
|
||
| / data timezone for incoming data timestamping - overwritten by init | ||
| datatimezone:`$"GMT"; | ||
|
|
||
| / offset from midnight for the eod roll - overwritten by init | ||
| rolltimeoffset:0D00:00:00.000; | ||
|
|
||
| / current trading date in rolltimezone - set by init | ||
| d:0Nd; | ||
|
|
||
| / utc timestamp of next eod roll - set by init | ||
| nextroll:0Wp; | ||
|
|
||
| / utc offset for datatimezone data stamping - set by init | ||
| dailyadj:0D00:00:00.000; | ||
|
|
||
| / ============================================================ | ||
| / internal helpers | ||
| / ============================================================ | ||
|
|
||
| normlog:{[logdict] | ||
| / detect kx.log instance by presence of kx.log-specific keys (getlvl, sinks, fmts) | ||
| / kx.log functions are monadic - wrap each into binary {[c;m]} and embed context in the message | ||
| / plain {[c;m]} log dicts (info`warn`error only) pass through unchanged | ||
| $[any `getlvl`sinks`fmts in key logdict; | ||
| `info`warn`error!( | ||
| {[fn;c;m] fn[string[c],": ",m]}[logdict`info;]; | ||
| {[fn;c;m] fn[string[c],": ",m]}[logdict`warn;]; | ||
| {[fn;c;m] fn[string[c],": ",m]}[logdict`error;]); | ||
| logdict] | ||
| }; | ||
|
|
||
| / returns timespan offset from utc for rolltimezone at timestamp p | ||
| adjtime:{[p] | ||
| / utc-equivalent timezones have zero offset | ||
| if[rolltimezone in utczones;:0D]; | ||
| `timespan$tz.gmttolocal[rolltimezone;p]-p | ||
| }; | ||
|
|
||
| / returns the date in rolltimezone for utc timestamp p | ||
| getday:{[p]"d"$(p+adjtime[p])-rolltimeoffset}; | ||
|
|
||
| / ============================================================ | ||
| / public api | ||
| / ============================================================ | ||
|
|
||
| / recomputes utc offset for datatimezone at current time | ||
| / call after an eod roll to get a fresh offset - important when datatimezone observes dst | ||
| getdailyadjustment:{ | ||
| / utc-equivalent timezones have zero offset | ||
| if[datatimezone in utczones;:0D]; | ||
| `timespan$tz.gmttolocal[datatimezone;.z.p]-.z.p | ||
| }; | ||
|
|
||
| / returns utc timestamp of next eod roll after utc timestamp p | ||
| getroll:{[p] | ||
| / mod[z,1D] normalises the roll time to [0D,1D) to handle timezone offsets crossing midnight | ||
| z:rolltimeoffset-adjtime[p]; | ||
| z:`timespan$(mod) . "j"$z,1D; | ||
| / kdb-x 5.0: comparing timespan to timestamp checks against p's time-of-day component - true means roll has already passed | ||
| ("d"$p)+$[z<=p;z+1D;z] | ||
| }; | ||
|
|
||
| / state getters | ||
| getd:{d}; | ||
| getnextroll:{nextroll}; | ||
| getdailyadj:{dailyadj}; | ||
|
|
||
| / state setters | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since these variables are dependent on each other would it be safer if there was just one setter function that updated them all together? E.g. if we had then after EOD, a TP would just need to call I know TorQ tickerplant.q sets them separately, but now that we have to do it via explicit setter functions, exposing three different setter functions might give the impression that they can be called independently. |
||
| setnextroll:{.z.m.nextroll:x}; | ||
| setdailyadj:{.z.m.dailyadj:x}; | ||
| setd:{.z.m.d:x}; | ||
|
|
||
| init:{[configs] | ||
| / initialise the eodtime module - validate deps, apply config, compute initial state | ||
| / configs: dict containing `log (required) plus optional `rolltimezone, `datatimezone, `rolltimeoffset | ||
| / log dep: `info`warn`error!({[c;m]};{[c;m]};{[c;m]}) - binary, c=context symbol, m=string | ||
| / examples: | ||
| / eodtime.init[enlist[`log]!enlist logdep] | ||
| / eodtime.init[`log`rolltimezone!(logdep;`$"Europe/London")] | ||
| if[99h<>type configs; | ||
| '"di.eodtime: configs must be a dict with `log key"]; | ||
| if[not `log in key configs; | ||
| '"di.eodtime: log dependency is required; pass `info`warn`error!(infofn;warnfn;errfn) keyed on `log"]; | ||
| if[99h<>type configs`log; | ||
| '"di.eodtime: log value must be a dict; pass `info`warn`error functions"]; | ||
| if[not all `info`warn`error in key configs`log; | ||
| '"di.eodtime: log dict must have `info`warn`error keys; got: ",(", " sv string key configs`log)]; | ||
| .z.m.log:normlog configs`log; | ||
| .z.m.rolltimezone:$[`rolltimezone in key configs;configs`rolltimezone;`$"GMT"]; | ||
| .z.m.datatimezone:$[`datatimezone in key configs;configs`datatimezone;`$"GMT"]; | ||
| .z.m.rolltimeoffset:$[`rolltimeoffset in key configs;configs`rolltimeoffset;0D00:00:00.000]; | ||
| .z.m.dailyadj:getdailyadjustment[]; | ||
| .z.m.d:getday[.z.p]; | ||
| .z.m.nextroll:getroll[.z.p]; | ||
| .z.m.log[`info][`eodtime;"initialised with rolltimezone=",string[rolltimezone]," datatimezone=",string[datatimezone]," rolltimeoffset=",string rolltimeoffset]; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| / end-of-day time management - date resolution, roll scheduling and data timestamp adjustment | ||
|
|
||
| tz:use`di.tz | ||
|
|
||
| \l ::eodtime.q | ||
|
|
||
| export:([init;getd;getnextroll;getdailyadj;getroll;getdailyadjustment;setnextroll;setdailyadj;setd]) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| action,ms,bytes,lang,code,repeat,minver,comment | ||
| comment,,,,,,,setup - load module and initialise with gmt defaults and log dep | ||
| before,0,0,q,eodtime:use`di.eodtime,1,1,load di.eodtime module | ||
| before,0,0,q,logdep:`info`warn`error!({[c;m]};{[c;m]};{[c;m]}),1,1,silent no-op log mock - binary {[c;m]} matches the log contract | ||
| before,0,0,q,eodtime.init[`rolltimezone`datatimezone`rolltimeoffset`log!(`$"GMT";`$"GMT";0D00:00:00.000;logdep)],1,1,init with gmt defaults and log dep | ||
| comment,,,,,,,getd | ||
| true,0,0,q,-14h=type eodtime.getd[],1,1,getd returns date type | ||
| comment,,,,,,,getnextroll | ||
| true,0,0,q,-12h=type eodtime.getnextroll[],1,1,getnextroll returns timestamp type | ||
| true,0,0,q,eodtime.getnextroll[]>.z.p,1,1,getnextroll returns future timestamp | ||
| comment,,,,,,,getdailyadj | ||
| true,0,0,q,-16h=type eodtime.getdailyadj[],1,1,getdailyadj returns timespan type | ||
| true,0,0,q,0D=eodtime.getdailyadj[],1,1,getdailyadj returns 0D for gmt datatimezone | ||
| comment,,,,,,,getdailyadjustment | ||
| true,0,0,q,-16h=type eodtime.getdailyadjustment[],1,1,getdailyadjustment returns timespan type | ||
| true,0,0,q,0D=eodtime.getdailyadjustment[],1,1,getdailyadjustment returns 0D for gmt datatimezone | ||
| comment,,,,,,,getroll - gmt zero offset | ||
| true,0,0,q,-12h=type eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,getroll returns timestamp type | ||
| true,0,0,q,2025.01.02D00:00:00.000000000=eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,getroll returns next midnight for gmt zero offset | ||
| comment,,,,,,,getroll - gmt with rolltimeoffset | ||
| run,0,0,q,eodtime.init[`rolltimezone`datatimezone`rolltimeoffset`log!(`$"GMT";`$"GMT";0D17:00:00.000;logdep)],1,1,reinit with 5pm gmt roll time | ||
| true,0,0,q,2025.01.01D17:00:00.000000000=eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,getroll returns todays 5pm when before roll time | ||
| true,0,0,q,2025.01.02D17:00:00.000000000=eodtime.getroll[2025.01.01D18:00:00.000000000],1,1,getroll returns next day 5pm when past roll time | ||
| comment,,,,,,,setnextroll | ||
| run,0,0,q,eodtime.init[`rolltimezone`datatimezone`rolltimeoffset`log!(`$"GMT";`$"GMT";0D00:00:00.000;logdep)],1,1,reinit with gmt defaults | ||
| run,0,0,q,eodtime.setnextroll[2025.06.01D00:00:00.000000000],1,1,setnextroll does not error | ||
| true,0,0,q,2025.06.01D00:00:00.000000000=eodtime.getnextroll[],1,1,getnextroll reflects setnextroll | ||
| comment,,,,,,,setdailyadj | ||
| run,0,0,q,eodtime.setdailyadj[0D01:00:00.000000000],1,1,setdailyadj does not error | ||
| true,0,0,q,0D01:00:00.000000000=eodtime.getdailyadj[],1,1,getdailyadj reflects setdailyadj | ||
| comment,,,,,,,setd | ||
| run,0,0,q,eodtime.setd[2025.06.01],1,1,setd does not error | ||
| true,0,0,q,2025.06.01=eodtime.getd[],1,1,getd reflects setd | ||
| comment,,,,,,,utc-equivalent timezone shortcuts (GMT/UTC/Etc/GMT) | ||
| run,0,0,q,eodtime.init[`rolltimezone`datatimezone`rolltimeoffset`log!(`$"UTC";`$"Etc/GMT";0D00:00:00.000;logdep)],1,1,reinit with UTC/Etc/GMT shortcuts | ||
| true,0,0,q,0D=eodtime.getdailyadjustment[],1,1,Etc/GMT datatimezone returns 0D without lookup | ||
| true,0,0,q,2025.01.02D00:00:00.000000000=eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,UTC rolltimezone returns correct roll | ||
| comment,,,,,,,non-gmt rolltimezone (Europe/London) | ||
| run,0,0,q,eodtime.init[`rolltimezone`datatimezone`rolltimeoffset`log!(`$"Europe/London";`$"GMT";0D00:00:00.000;logdep)],1,1,reinit with London rolltimezone | ||
| true,0,0,q,-12h=type eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,getroll returns timestamp type for non-gmt rolltimezone | ||
| true,0,0,q,2025.01.02D00:00:00.000000000=eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,getroll correct for london winter (utc+0) | ||
| true,0,0,q,2025.07.01D23:00:00.000000000=eodtime.getroll[2025.07.01D12:00:00.000000000],1,1,getroll correct for london summer (utc+1 - midnight local is 23:00 utc) | ||
| comment,,,,,,,non-gmt datatimezone (Europe/London - DST aware) | ||
| run,0,0,q,eodtime.init[`rolltimezone`datatimezone`rolltimeoffset`log!(`$"GMT";`$"Europe/London";0D00:00:00.000;logdep)],1,1,reinit with London datatimezone | ||
| true,0,0,q,-16h=type eodtime.getdailyadjustment[],1,1,Europe/London datatimezone returns timespan type | ||
| true,0,0,q,0D<=eodtime.getdailyadjustment[],1,1,Europe/London datatimezone returns non-negative offset | ||
| comment,,,,,,,init - empty config (just log dep) applies all defaults | ||
| run,0,0,q,eodtime.init[enlist[`log]!enlist logdep],1,1,init with just log dep applies all defaults | ||
| true,0,0,q,0D=eodtime.getdailyadj[],1,1,default datatimezone (GMT) produces zero daily adjustment | ||
| true,0,0,q,0D=eodtime.getdailyadjustment[],1,1,default datatimezone (GMT) produces zero computed adjustment | ||
| true,0,0,q,2025.01.02D00:00:00.000000000=eodtime.getroll[2025.01.01D12:00:00.000000000],1,1,default rolltimeoffset (0D) gives midnight roll | ||
| comment,,,,,,,init - non-dict configs throws | ||
| fail,0,0,q,eodtime.init[(::)],1,1,errors when configs is not a dictionary | ||
| comment,,,,,,,error cases | ||
| fail,0,0,q,eodtime.getroll[`notvalid],1,1,getroll throws on non-timestamp input | ||
| comment,,,,,,,init - dep validation | ||
| fail,0,0,q,eodtime.init[()!()],1,1,errors when log dependency is missing | ||
| fail,0,0,q,eodtime.init[enlist[`log]!enlist 42],1,1,errors when log value is not a dictionary | ||
| fail,0,0,q,eodtime.init[enlist[`log]!enlist `info`warn!(logdep`info;logdep`warn)],1,1,errors when log dict is missing the error key | ||
| run,0,0,q,.test.err:@[{eodtime.init[()!()]};(::);{x}],1,1,capture error string from init with missing log dep | ||
| true,0,0,q,.test.err like "di.eodtime:*",1,1,error is prefixed di.eodtime: | ||
| comment,,,,,,,init - kx.log instance normalised automatically (no manual wrapping required) | ||
| run,0,0,q,kxlogger:use`kx.log,1,1,load kx.log | ||
| run,0,0,q,kxinst:kxlogger.createLog[],1,1,create kx.log instance | ||
| run,0,0,q,eodtime.init[`log`rolltimezone!(kxinst;`$"GMT")],1,1,bare kx.log instance accepted without wrapping | ||
| run,0,0,q,.m.di.0eodtime.log[`info][`eodtime;"normalisation test"],1,1,normalised logger accepts binary {[c;m]} call without error | ||
| comment,,,,,,,log call verification - capturing logger sees init message with binary {[c;m]} args | ||
| run,0,0,q,caplog:`info`warn`error!({[c;m] `.test.cap upsert(`info;m)};{[c;m] `.test.cap upsert(`warn;m)};{[c;m] `.test.cap upsert(`error;m)}),1,1,capturing log mock - binary {[c;m]} | ||
| run,0,0,q,.test.cap:([] fn:`symbol$();msg:()),1,1,initialise log capture table | ||
| run,0,0,q,eodtime.init[enlist[`log]!enlist caplog],1,1,init with capturing logger | ||
| true,0,0,q,1=count select from .test.cap where fn=`info,1,1,one info entry captured on init | ||
| true,0,0,q,any (.test.cap`msg) like "initialised*",1,1,log message confirms initialisation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of these are in the export dict so should be moved to the "public api" section