Skip to content

Document record-structure dictionary counts and the encoding they measure - #633

Merged
Ethan-Arrowood merged 8 commits into
mainfrom
kris/2220-structure-metric
Aug 26, 2026
Merged

Document record-structure dictionary counts and the encoding they measure#633
Ethan-Arrowood merged 8 commits into
mainfrom
kris/2220-structure-metric

Conversation

@kriszyp

@kriszyp kriszyp commented Aug 20, 2026

Copy link
Copy Markdown
Member

Companion to the core change for HarperFast/harper#2220 — Per-table msgpackr structure dictionaries grow unbounded and unobservably, which adds four fields to describe_table: typed_structures_enabled, typed_structure_count, typed_structure_limit, classic_structure_count.

Documents what a record structure is, why the dictionary only ever grows, what reaching the bound means, and how an application keeps it small — and, in response to review, documents the feature those counts describe. storage.randomAccessFields had shipped in v5.1.0 with no documentation anywhere: not in the configuration option list, not on the @table directive, and nothing explaining what the encoding buys or which tables it suits. The describe_table passage was a reader's first encounter with it. So the PR now adds a Record Encoding section to Storage Tuning covering the layout difference, what each encoding buys, when to enable it and when not to, plus the config option and the @table argument in their reference lists.

For the human reviewer

  • The growth model is the part worth checking. A structure is minted per distinct shape = ordered field list × each field's encoded type and width — so {a, b} and {b, a} are different shapes, and so are {v: 1}, {v: 70000}, and {v: "ok"}. This is measured against the installed deps, not inferred: 4 key orders → 4 structures; one two-field shape across 11 value kinds → 5 structures. The issue that prompted this attributed growth to realized field subsets alone, which understates it.
  • The classic bound is newly stated and is the claim to check hardest. classic_structure_count stops at 32 because msgpackr's shared named-record list defaults to maxSharedStructures: 32 (msgpackr/pack.js:43). Verified empirically — a Packr with getStructures/saveStructures fed 200 distinct field-name sets saturates the shared list at exactly 32 — and it matches the core PR's live measurement (typed 256/256, classic 32). That is why describe_table reports no classic_structure_limit: there is a bound, it is just not configurable.
  • "Safe to toggle at runtime" was wrong and is now stated as restart-scoped. OpenDBIObject reads storage.randomAccessFields when the primary DBI is constructed, so an already-open table keeps the encoding it opened with. An operator who runs set_configuration and immediately polls describe_table would otherwise conclude the feature is broken.
  • typed_structures_enabled needs the surrounding sentence. storage.randomAccessFields defaults off, so most tables show typed_structure_count: 0 against a limit of 256. Without the explanation an operator reads that as spare headroom rather than the feature being disabled, so the paragraph saying so is load-bearing.
  • The warning's scope is stated honestly rather than simply. It fires per encoder from the post-save path, so several workers can each warn for one table and a worker that never saves after loading a full dictionary stays silent. The text says the counts are the reliable signal and the log is the heads-up, rather than implying one warning per table.
  • The bound is now referred to by its reported field (typed_structure_count against typed_structure_limit, 256 by default) rather than as a literal "256 per encoder", which read as conflicting with describe_table presenting one count per table.
  • Not done, deliberately: storage.randomAccessFields and the @table(randomAccessFields:) directive are v5.1.0 surface with no entry in release-notes/v5-lincoln/5.1.md. Backfilling a shipped release-notes file felt like a separate call rather than something to fold in here.
  • No analytics metric is documented, deliberately. The core change originally folded these counts onto the table-size metric; that metric turns out to have no RocksDB emitter at all (The table-size analytics metric is never emitted on RocksDB harper#2249), so documenting it here would point operators at a series that never appears.

Verification

  • npm run format:check clean; npm run build succeeds with no new broken links or anchors (the two it reports — /reference/v5/backups/overview and /release-notes/v5-lincoln/5.1 — are pre-existing and on untouched pages).
  • The classic-dictionary bound of 32 confirmed by running a Packr with shared structures over 200 distinct field-name sets against Harper's installed msgpackr.
  • Claims cross-checked against the core diff (Make per-table record-structure dictionary size observable harper#2250) and against live measurements from the core PR's integration suite (a saturated table reports typed 256/256, classic 32).

Refs HarperFast/harper#2220

Review-Coverage: authored=codex; ran=gemini,claude; declined=cursor-grok,cursor-composer,domain; rounds=4 @ cecf65b

Human-Review-Need: 2 @ cecf65b

@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 updates the 'describe_table' API documentation to detail the new record-structure dictionary fields in the response. The reviewer suggested adding a version badge to indicate this behavior change, as per the repository's documentation guidelines.

Comment thread reference/operations-api/operations.md
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-633

This preview will update automatically when you push new commits.

@github-actions
github-actions Bot temporarily deployed to pr-633 August 21, 2026 21:48 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-633

This preview will update automatically when you push new commits.

@kriszyp
kriszyp marked this pull request as ready for review August 24, 2026 14:56
@kriszyp
kriszyp requested a review from a team as a code owner August 24, 2026 14:56
Comment thread reference/operations-api/operations.md
kriszyp added a commit that referenced this pull request Aug 24, 2026
The describe_table structure counts were a reader's first encounter with
storage.randomAccessFields, which had no documentation anywhere: not in
the configuration option list, not on the @table directive, and nowhere
explaining what the encoding buys or which tables it suits.

Add a Record Encoding section to Storage Tuning covering the layout
difference between the classic and typed encodings, what each buys,
when to enable it and when to leave it off, the runtime-toggle and
per-table pinning semantics, and the structure bound. Add the config
option and the @table argument to their reference lists, and point the
describe_table passage at the new material.

Refs #633

Co-Authored-By: Claude Opus <noreply@anthropic.com>
kriszyp added a commit that referenced this pull request Aug 24, 2026
- A structure keys on each field's encoded type as well as its width, so
  a field written as an integer in one record and a string in the next
  mints a new one. The shape definition and the shape-stabilization
  advice both said "width class" only.
- "Safe to toggle at runtime" read as "takes effect at runtime". A table
  reads the setting when its store opens, so like every other config
  change it lands on restart; say that instead.
- State the typed bound as the reported typed_structure_limit rather
  than a literal 256 per encoder, which conflicted with describe_table
  presenting one count per table.
- Give classic_structure_count an interpretation: it keys on field names
  alone and stops at 32, which is why the response carries no limit
  field for it.
- Note that pinning a table's encoding also means a fleet-wide change to
  the global setting will not move it.
- Cross-link Storage Algorithm to the new section, and the @table
  argument row to its explanation.

Refs #633

Co-Authored-By: Claude Opus <noreply@anthropic.com>
@kriszyp kriszyp changed the title Document record-structure dictionary counts on describe_table Document record-structure dictionary counts and the encoding they measure Aug 24, 2026
@github-actions
github-actions Bot temporarily deployed to pr-633 August 24, 2026 15:52 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-633

This preview will update automatically when you push new commits.

@Ethan-Arrowood
Ethan-Arrowood enabled auto-merge (squash) August 26, 2026 22:30
kriszyp and others added 8 commits August 26, 2026 16:46
Companion to harper core's observability change for HarperFast/harper#2220.
Explains what a record structure is, why the dictionary only grows, what
reaching the bound means, and how to keep the dictionary small.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Repo convention (AGENTS.md): behavior changes to an existing surface carry
`<VersionBadge type="changed" version="vX.Y.0" />`. Patch-level badges have
precedent in reference/ (v5.1.5, v5.1.13, v5.1.15), and main is at 5.2.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The describe_table structure counts were a reader's first encounter with
storage.randomAccessFields, which had no documentation anywhere: not in
the configuration option list, not on the @table directive, and nowhere
explaining what the encoding buys or which tables it suits.

Add a Record Encoding section to Storage Tuning covering the layout
difference between the classic and typed encodings, what each buys,
when to enable it and when to leave it off, the runtime-toggle and
per-table pinning semantics, and the structure bound. Add the config
option and the @table argument to their reference lists, and point the
describe_table passage at the new material.

Refs #633

Co-Authored-By: Claude Opus <noreply@anthropic.com>
- A structure keys on each field's encoded type as well as its width, so
  a field written as an integer in one record and a string in the next
  mints a new one. The shape definition and the shape-stabilization
  advice both said "width class" only.
- "Safe to toggle at runtime" read as "takes effect at runtime". A table
  reads the setting when its store opens, so like every other config
  change it lands on restart; say that instead.
- State the typed bound as the reported typed_structure_limit rather
  than a literal 256 per encoder, which conflicted with describe_table
  presenting one count per table.
- Give classic_structure_count an interpretation: it keys on field names
  alone and stops at 32, which is why the response carries no limit
  field for it.
- Note that pinning a table's encoding also means a fleet-wide change to
  the global setting will not move it.
- Cross-link Storage Algorithm to the new section, and the @table
  argument row to its explanation.

Refs #633

Co-Authored-By: Claude Opus <noreply@anthropic.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
@kriszyp
kriszyp force-pushed the kris/2220-structure-metric branch from 458332b to cecf65b Compare August 26, 2026 23:10
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-633

This preview will update automatically when you push new commits.

@github-actions
github-actions Bot temporarily deployed to pr-633 August 26, 2026 23:13 Inactive
@Ethan-Arrowood
Ethan-Arrowood merged commit ca6143e into main Aug 26, 2026
11 checks passed
@Ethan-Arrowood
Ethan-Arrowood deleted the kris/2220-structure-metric branch August 26, 2026 23:14
@github-actions

Copy link
Copy Markdown

🧹 Preview Cleanup

The preview deployment for this PR has been removed.

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.

4 participants