Skip to content

docs(plans): design json_tree tokens derivable from the path alone - #1361

Draft
coderdan wants to merge 2 commits into
fix/json-tree-extracted-entry-checkfrom
docs/json-tree-derivable-tokens
Draft

coderdan wants to merge 2 commits into
fix/json-tree-extracted-entry-checkfrom
docs/json-tree-derivable-tokens

Conversation

@coderdan

Copy link
Copy Markdown
Contributor

Summary

A write-up only: no code changes. EQL v4's json_tree column stores an encrypted JSON document as one entry per JSON node. To read part of one, the client sends the database a token, a secret derived from the path that lets the database map the structure under that node in every row. Today an object member's token mixes in its place among its siblings, which the client cannot know. So a read of $.profile.address.city has to send the token of the whole $.profile field. The same cause is behind #1356, and the fix proposed in #1359 widens the leak further. This PR records the agreed change that removes it (tracked in #1360):

  • an object member's token no longer depends on its siblings, so the client derives the token of exactly the node it reads;
  • every entry gets an 8-byte self tag, so a read can return the node itself;
  • the client expands wildcards into concrete paths with a bound, and the gates go away.

It also revises the leakage page to say what the database learns after the change. It lists eight open questions, found while checking the design against the code, for the owner to answer before implementation starts.

Changes

  • docs/plans/2026-10-17-json-tree-index.md: a new dated section, "Design change (2026-10-24): derivable tokens, the self tag, and wildcard expansion on the client". It covers why, then the token rules, the self tag, wildcard expansion and the new SQL read, the client's checks, the wire change, the leakage, the plan with its test list and benchmark step, and the open questions. One-line dated pointers sit where sections 2, 4 and 6, the Phase 1/2 deviations and the Phase 3b notes state what the change reverses. Nothing earlier is rewritten.
  • packages/eql/docs/reference/json-tree-leakage.md: the subtree-read bullet (exact tokens, wildcard expansion and its probe, the root), a new row for the self tag x in the at-rest table, x in the list of fields that are not authenticated, the walk check, the comparison row, and the sealed_root option.

Do not merge this ahead of the implementation. The leakage page will then describe a format that is not built yet. The plan is to stack the implementation on this branch so the two land together.

No changeset: this changes documentation only, in the repository's design record and the EQL reference page, and no published package's surface.

Verification

  • bash tasks/test/doc-anchors.sh in packages/eql (with EQL_ROOT set to the subtree): doc-anchor gate OK — 123 intra-document link(s) resolve.
  • docs:validate:source was not run: it checks the --! comments in the SQL sources only, and this PR changes no SQL.
  • grep eql_v2 on the leakage page: no match (what test:docs_v3_grep checks).
  • I read both tables back after editing; each row keeps its column count.
  • I checked every code claim in the section against this branch (fix(stack-encrypt): check that a json_tree read returns the entry asked for #1358's): child_token, parent_tag, rank / shuffled_ordinals, entry_aad, the walk's head derivation, and subtree_key_for in packages/stack-encrypt/src/json/derive.rs; selector_bytes / token_bytes in path.rs; and json_tree_child_token, json_tree_subtree_at and the walk's "bound" comment in packages/eql/src/v3/json_tree/functions.sql.

Related

Refs #1360 (the issue this designs).
Refs #1356 (solved as a side effect), #1359 (superseded in mechanism; its behaviour and oracle test carry over), #1358 (base branch; its checks are adapted), #1357 (unchanged by this), #1345 (should merge before #1358).

https://claude.ai/code/session_01N7bCqa3ZVJMcEE99RzVqEu

An object member's token mixes in its ordinal, a keyed rank among its
siblings that the client cannot know for a row it has not read. So the
client can derive a token only for a top-level field and the array
positions after it, and walks the rest through gates. A read of
$.profile.address.city therefore sends $.profile's token, a capability
over that whole field in every row, and the fix proposed for #1356
widens that further by sending an array's token to read one element.

Record the agreed change: member tokens drop the ordinal, every entry
gains an eight-byte self tag so a read can find a node from its own
token and return it at depth 0, and the client expands wildcards into
concrete paths with a bound and a probe, so gates and
json_tree_subtree_at go away. The section gives the derivations, the
SQL read, the adapted client check, the wire change, the leakage, the
implementation and measurement plan, and the inconsistencies found
while checking the design against the code, as open questions for the
owner. Short dated pointers mark where sections 2, 4 and 6 and the
Phase 3b notes state what the change reverses.

Claude-Session: https://claude.ai/code/session_01N7bCqa3ZVJMcEE99RzVqEu
The leakage page told customers that a subtree read sends the token of
the top-level field the path starts with. Under the design change in
the json_tree design record, a read sends the token of exactly the node
asked for, a wildcard sends a bounded list of concrete tokens and one
probe per level, and every entry carries a self tag. Revise the subtree
read bullet, add the self tag to the at-rest table and the
unauthenticated fields, adapt the walk check, the comparison row and
the sealed_root option, so the page describes the format the
implementation stacked on this branch will build.

Claude-Session: https://claude.ai/code/session_01N7bCqa3ZVJMcEE99RzVqEu
@changeset-bot

changeset-bot Bot commented Oct 24, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: edabee6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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.

1 participant