docs: QueryTag error = InvalidPacketId (72); needs native aahClient.dll RE

Deepened the R0.1 browse finding. QueryTag's constant rejection decodes to
ArchestrA.CloudHistorian.Contract.ErrorCode.InvalidPacketId (72): the btRequest needs
a QueryTag-specific packet-id header (the generic 0x6751/v1 header StartTagQuery accepts
is rejected). The semantic fields are known from CloudHistorian.Contract
(QueryHandle/QueryType/StartIndex/TagCount request; TagNames[]+TagMetadataBuffer response),
but the binary packet framing lives in native aahClient.dll — aahClientManaged.dll is
mixed-mode (ilspycmd cannot decompile it) and no managed assembly builds the buffer.
Finishing QueryTag needs native RE (Ghidra/IDA) or a live gRPC capture of the stock client.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
Joseph Doherty
2026-06-21 15:16:19 -04:00
parent 26ef5e5645
commit 4c9f0d476c
@@ -28,15 +28,26 @@ Success response `btResponse` is the 8-byte `(queryHandle:uint, tagCount:uint)`
`*` → empty, `Pre*` → `startswith(TagName,'Pre')`, `*sub*` → `contains(TagName,'sub')`,
exact → `TagName eq '...'`. (Escaping single-quotes in names still TBD.)
## QueryTag — OPEN (one capture away)
## QueryTag — OPEN (needs native RE of aahClient.dll)
`QueryTag(strHandle, uiQueryHandle, btRequest)` is the paging call that should return the actual
tag-name rows. Every `btRequest` shape tried returns a constant native error **type 4 / code 72**
(independent of content: empty, count, column-name historian-string, `$select=TagName`,
marker+version+name all give the same `04 48000000`). The constant code regardless of input means the
request *framing* is wrong, not the field values — this needs a **native capture** of the real 2023 R2
client driving a browse to recover the exact `QueryTag` `btRequest` (and the row framing in
`btResonse`). Do not ship a guessed QueryTag request (project discipline: no guessed wire bytes).
`QueryTag(strHandle, uiQueryHandle, btRequest)` is the paging call that returns the tag-name rows.
Every `btRequest` shape tried returns the constant native error **type 4 / code 72 =
`InvalidPacketId`** (`ArchestrA.CloudHistorian.Contract.ErrorCode.InvalidPacketId = 72`; the empty
buffer alone gives a different code). So the `btRequest` must carry a **packet-id header specific to
QueryTag** that we don't have — the generic `0x6751`/version-1 header (which StartTagQuery accepts) is
rejected here.
**Semantic fields are known** from `ArchestrA.CloudHistorian.Contract`:
- request `QueryTagRequest` = `QueryHandle:uint("q") + QueryType:ushort("t") + StartIndex:uint("s") + TagCount:uint("c")`
- response `QueryTagResponse` = `QueryHandle:uint + TagNames:string[]("t") + NextIndex:uint("i") + TagMetadataBuffer:byte[]("tb")`
— so QueryTag returns the names directly (plus an optional metadata buffer), and pages via StartIndex/NextIndex.
What's missing is the **binary `btRequest` packet framing** (the QueryTag packet id + how those fields
are laid out). That serializer lives in **native `aahClient.dll`** — `aahClientManaged.dll` is
**mixed-mode (C++/CLI)** so ilspycmd cannot decompile it, and no managed assembly builds the buffer.
Completing QueryTag therefore requires **native RE (Ghidra/IDA on `aahClient.dll`)** or a **live gRPC
capture** of the stock 2023 R2 client browsing. Do not ship a guessed QueryTag request (project
discipline: no guessed wire bytes).
Probe helpers live in `Grpc/HistorianGrpcTagClient` (`ProbeStartTagQuery`, `ProbeTagQuerySequence`)
and the gated `StartTagQuery_OverGrpc_AcceptsODataFilter` test pins the StartTagQuery+OData result.