feat(storage): show column descriptions in table-detail human output - #642
Merged
Conversation
0.88.0 (#624) moved the column-description write to the native `PUT .../tables/{id}/definition` endpoint precisely so the text would show up everywhere: the Keboola UI, the MCP server's `get_tables`, and the Snowflake COMMENT / BigQuery column description. `--json` carried it too, on `column_details[].description`. kbagent's own human-mode Columns table was the one surface still showing nothing -- so `storage describe-column` followed by `storage table-detail`, the obvious way to check your own work, was the one way that did not work. Add a `Description` column to that Rich table: * Shown only when at least one column actually has a description, matching `render_table_layout`'s existing "no data, no chrome" rule -- an undocumented table's output is byte-identical to before. * Wrapped and width-capped, never truncated. Verifying what you just wrote is the point, so an ellipsis would defeat it; `overflow="fold"` breaks even a long unbroken token rather than hiding its tail, and `max_width=60` stops a wide terminal from stretching the cell across the screen. * Escaped. Descriptions are user-authored free text, and Rich would otherwise read `[note]` as markup (or raise on an unbalanced tag). `--json` is untouched. All three description tiers the service already resolves (native definition, `columnMetadata` KBC.description, legacy flat key) render, and the legacy-key migration warning still prints below. Tests cover the render, the empty-column guard, markup escaping, wrapping at 80 columns, and the width cap at 200; each was verified to fail against the matching mutation of the production code. Note that the 80-column case has to override conftest's autouse `COLUMNS=200` fixture explicitly -- without that it silently asserts nothing.
v0.88.0 shipped earlier today, so this change belongs to whatever version comes next -- but that number is the release step's to choose, not this PR's. Reverts pyproject/plugin.json/marketplace.json/uv.lock to 0.88.0 and removes the 0.88.1 changelog key (an entry with no matching release fails `make changelog-check`). The doc surfaces no longer name 0.88.1 either. `make version-gate-check` rejects any `(since vX.Y.Z)` marker that is not a CHANGELOG key -- an agent reading a gate for a version that never ships refuses a command the user actually has. The three notes now anchor on 0.88.0, a real release, and say what that version does NOT do: "Human mode's Columns table shows a Description column. On 0.88.0 it did NOT -- there the descriptions were readable only through --json, so a blank-looking terminal table on that version does not mean the write failed." That is true regardless of the number this eventually ships under. gotchas.md carries an explicit release-step reminder to tag it once known.
padak
added a commit
that referenced
this pull request
Aug 22, 2026
…has.md Both '(Release step: once this ships, tag this sentence (since vX.Y.Z)...)' parentheticals in the storage-descriptions gotcha referred to behavior that has since merged: the table-detail human-mode Description column (#642) and the describe-batch --from-file shape rejection (#645). Neither commit is contained in the v0.88.0 tag and main is bumped to 0.89.0, so both are tagged (since v0.89.0) -- a version version-gate-check resolves via its existing changelog entry. This is a live instance of the leftover-placeholder failure mode this PR's release checklist step 4 now guards against.
This was referenced Aug 22, 2026
padak
added a commit
that referenced
this pull request
Aug 22, 2026
pyproject/plugin.json/marketplace.json were already renumbered to 0.89.0 by v0.88.0. Changelog: adds 0.89.0 entries for #645 (describe-batch --from-file shape validation, issue #640), #642 (table-detail human column descriptions), #620 (sync-action forwards root authorization/runtime), #517 (stable metavar contract, issue #513), #586 (documented prompt budget gated against the enforced one, issue #585) and #641 (docs-only), and decorates the existing Silent-drift surfaces: * gotchas.md -- resolves both "(Release step: ... tag this sentence)" placeholders. Both were left by commits AFTER the v0.88.0 tag (#642 and #645), so both are tagged (since v0.89.0), not 0.88.0. Adds the #620 gotcha: below 0.89.0 a sync action on an OAuth / Service-Account component died with an opaque empty-body 400 because the broker reference was never forwarded. * #620 shipped with no doc surfaces at all -- CLAUDE.md, AGENT_CONTEXT and commands-reference.md now carry the forwarding rule (root only, never row-overridden, only when non-empty) with its version gate. * #645 never reached CLAUDE.md -- the describe-batch shape check and its behaviour change are recorded there now; commands-reference gains the version tag. * #642's human Description column is version-tagged in CLAUDE.md, commands-reference.md, AGENT_CONTEXT and storage-describe-workflow.md. * #643 was otherwise complete; adds the two surfaces it did not touch -- safe-write-workflow.md (delete is reversible; never blind-retry on <= 0.88.x) and a keboola-expert.md matrix row for delete/restore/trash-list. keboola-expert.md is 49 774 B, well inside the 70 000 B budget. make check green: 5934 passed, 12 skipped. version-gate-check resolves all 438 markers across 72 versions.
padak
added a commit
that referenced
this pull request
Aug 23, 2026
#648) * docs: stop bumping the version in feature PRs; releases become dedicated release PRs Parallel feature PRs (one AI session per issue) each bumping pyproject.toml collide on every merge and silently renumber releases -- the KNOWN_UNRELEASED list in scripts/generate_changelog.py is the accumulated damage of that pattern. Version bumps and changelog.py entries now happen ONLY in a dedicated release PR that batches everything merged since the last release. - CLAUDE.md Versioning: new 'Version bumps happen ONLY in a dedicated release PR' subsection with the two-step flow and the vNEXT placeholder convention for version-gated docs in feature PRs (version-gate-check rejects guessed numeric versions in per-PR CI, so the placeholder is the only workable tag before the release assigns a number). - CONTRIBUTING.md: new 'No version bumps in feature PRs' commit convention; per-command gotchas checklist and sync map updated for vNEXT; 'Releasing a new version' rewritten around the release PR -- new step 1 (collect merged PRs since the last tag as the exact scope of the changelog and release notes) and step 4 (replace every vNEXT, grep must come back empty); beta releases documented as the one deliberate exception where the bump rides the feature branch. * docs(plugin): resolve the two stale release-step placeholders in gotchas.md Both '(Release step: once this ships, tag this sentence (since vX.Y.Z)...)' parentheticals in the storage-descriptions gotcha referred to behavior that has since merged: the table-detail human-mode Description column (#642) and the describe-batch --from-file shape rejection (#645). Neither commit is contained in the v0.88.0 tag and main is bumped to 0.89.0, so both are tagged (since v0.89.0) -- a version version-gate-check resolves via its existing changelog entry. This is a live instance of the leftover-placeholder failure mode this PR's release checklist step 4 now guards against.
padak
added a commit
that referenced
this pull request
Aug 23, 2026
pyproject/plugin.json/marketplace.json were already renumbered to 0.89.0 by v0.88.0. Changelog: adds 0.89.0 entries for #645 (describe-batch --from-file shape validation, issue #640), #642 (table-detail human column descriptions), #620 (sync-action forwards root authorization/runtime), #517 (stable metavar contract, issue #513), #586 (documented prompt budget gated against the enforced one, issue #585) and #641 (docs-only), and decorates the existing Silent-drift surfaces: * gotchas.md -- resolves both "(Release step: ... tag this sentence)" placeholders. Both were left by commits AFTER the v0.88.0 tag (#642 and #645), so both are tagged (since v0.89.0), not 0.88.0. Adds the #620 gotcha: below 0.89.0 a sync action on an OAuth / Service-Account component died with an opaque empty-body 400 because the broker reference was never forwarded. * #620 shipped with no doc surfaces at all -- CLAUDE.md, AGENT_CONTEXT and commands-reference.md now carry the forwarding rule (root only, never row-overridden, only when non-empty) with its version gate. * #645 never reached CLAUDE.md -- the describe-batch shape check and its behaviour change are recorded there now; commands-reference gains the version tag. * #642's human Description column is version-tagged in CLAUDE.md, commands-reference.md, AGENT_CONTEXT and storage-describe-workflow.md. * #643 was otherwise complete; adds the two surfaces it did not touch -- safe-write-workflow.md (delete is reversible; never blind-retry on <= 0.88.x) and a keboola-expert.md matrix row for delete/restore/trash-list. keboola-expert.md is 49 774 B, well inside the 70 000 B budget. make check green: 5934 passed, 12 skipped. version-gate-check resolves all 438 markers across 72 versions.
padak
added a commit
that referenced
this pull request
Aug 23, 2026
…es (#651) Release prep for 0.89.0: adds the changelog entries for everything merged since v0.88.0 (#620, #642, #643, #644, #645, #646, #647, #648, #649, #650, #517, #586, #641), resolves every vNEXT placeholder left by feature PRs to v0.89.0 per the new #648 release process, closes the 10 gaps a full doc-surface audit found across the kbagent plugin (SKILL.md triggers, commands-reference, gotchas, workflow files, keboola-expert.md, AGENT_CONTEXT, CLAUDE.md), and records the live e2e verification evidence. Version files were already at 0.89.0 (bumped by #643); make version-sync is a no-op.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
0.88.0 (#624) was specifically about making column descriptions visible everywhere: the write moved to the native
PUT .../tables/{id}/definitionendpoint so the text reaches the Keboola UI, the MCP server'sget_tables, and the SnowflakeCOMMENT/ BigQuery column description.--jsoncarried it too, oncolumn_details[].description.kbagent's own human-mode
Columnstable was the one surface still showing nothing. So this sequence — the obvious way to check your own work — was the one way that did not work:The column has never existed:
git log -S "Description" -- src/keboola_agent_cli/commands/_storage_table_detail.pyis empty.What changed
A
Descriptioncolumn on that Rich table, populated fromcol.get("description").Before / after (100-column terminal, all three description tiers):
Three decisions worth stating, since the issue left them open:
Hidden when empty. The column is added only when at least one column actually has a description — the same "no data, no chrome" rule
render_table_layoutalready follows for the partitioning lines. An undocumented table's output is byte-identical to before. This is a real emptiness test, not a test for"":services/_table_detail._column_detailssetsdescriptiononly when one of the three tiers resolved.Wrapped and capped, never truncated. Verifying what you just wrote is the whole point, so an ellipsis would defeat it.
overflow="fold"breaks even a long unbroken token instead of hiding its tail, andmax_width=60stops a wide terminal from stretching the cell across the screen while Rich shrinks it further on a narrow one. Both directions are asserted.Escaped. Descriptions are user-authored free text and Rich renders
strcells as markup —[note]would vanish and an unbalanced tag can raise.escape()matches what thedisplay_nameline above already does.--jsonis untouched. All three tiers the service already resolves (nativedefinition→columnMetadataKBC.description→ legacy flatKBC.column.*) render, and the legacy-key migration warning still prints below the table.Tests
Five tests in
TestColumnDescriptions, alongside the existing human-render tests for that module. Each was verified to fail against the matching mutation of the production code — dropmax_width→ the sprawl test dies; dropescape()→ the markup test dies; forceshow_description = True→ the empty-column test dies.One trap worth flagging for future readers, and called out in the test docstring:
tests/conftest.pyhas an autouse fixture pinningCOLUMNS=200for every test (added after a host-dependent width silently cut a value in half on Windows CI). A "fits in 80 columns" assertion that does not override it asserts nothing at all — the first draft of that test passed for the wrong reason.Version — no bump
Deliberately not bumped: v0.88.0 shipped earlier today and the next number is the release step's call, so this PR stays on
0.88.0and gets renumbered at release time.Two consequences worth knowing about, both handled:
No changelog key. A
0.88.1entry with no matching release failsmake changelog-check, so the entry was removed. Paste-ready text for whoever cuts the release:No
(since vX.Y.Z)markers.make version-gate-checkrejects a gate naming a version with no changelog entry — an agent reading a gate for a version that never ships refuses a command the user actually has. The three doc notes (CLAUDE.md,references/commands-reference.md,references/gotchas.md) therefore anchor on 0.88.0, a real release, and state what that version does not do: "On 0.88.0 it did NOT — there the descriptions were readable only through--json, so a blank-looking terminal table on that version does not mean the write failed." True whatever number this ships under.gotchas.mdcarries an inline release-step reminder to tag it once the version is known.make checkis green end to end: lint, format, SKILL.md, version sync, version gates, command sync, changelog completeness, error codes, sentinel guards, LOC budget, 5862 tests.