Skip to content

PRDCT-553: Generic Writer under Components › Writers (re-cut off main) - #1052

Open
Iamfle4ka wants to merge 3 commits into
mainfrom
PRDCT-553-generic-writer-recut
Open

PRDCT-553: Generic Writer under Components › Writers (re-cut off main)#1052
Iamfle4ka wants to merge 3 commits into
mainfrom
PRDCT-553-generic-writer-recut

Conversation

@Iamfle4ka

@Iamfle4ka Iamfle4ka commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Moves the 3 Generic Writer pages to /components/writers/generic-writer/, alongside the other data destination connectors. Old /extend/generic-writer/* URLs keep working via redirect_from.

Re-cut of phase-2 batch 3 (was #1032, stacked on the big-bang #1027) as a standalone per-unit PR off main, per the 2026-07-27 pivot.

Deep-review pass (2026-07-29)

Per your "each deserves attention individually… I want every line scrutinized" — every claim on these pages was checked against a source of truth. The move itself was faithful (no dropped sections, mangled tables, or leftover Liquid), but it shipped a rendering blocker, and the pages inherited a batch of factual errors from the upstream README.

Source of truth used

Component id kds-team.wr-generic (in-app name is just "Generic", type writer, vendor kds-team)
Repo bitbucket.org/kds_consulting_team/kds-team.wr-genericpublic and live (HTTP 200, master, updated 2025-02-13), so the ~29 Bitbucket links in these pages all still work. No GitHub mirror exists.
Schema src/configuration.py dataclasses. The Storage API configurationSchema is {} — this component is genericDockerUI, i.e. configured by raw JSON, which is why these pages are a JSON reference with no form-UI walkthrough.
Behavior src/component.py, src/json_converter.py, src/user_functions.py, src/http_generic/auth.py, plus the recorded functional examples in docs/examples/001–037

1. Rendering blocker (introduced by the phase-1 migration)

The inlined writer-config-map include produced ```json {} ``` — not a valid CommonMark fence pair. One 168-line code block swallowed lines 66–233, so ## Api, ### Base URL and ### Retry Config rendered as literal text and the #api / #base-url / #retry-config anchors did not exist (3 links in the config map pointed at them). Headings 34 → 37; longest code block 168 → 84 lines.

Also removed the 46-line jQuery <script> + <style> inlined from writer-config-events.js: there is no jQuery in this repo, its span:contains() selectors targeted Jekyll/Rouge markup (we render with Expressive Code), and 6 of its hardcoded anchors were wrong. Its purpose was to make the config map clickable, so I reworded the lede that promised that.

2. Claims the component's own code refutes

All inherited from the dev original — each is provable from the source or from a recorded functional example:

  • autodetect default is false, not true.
  • Four datatypes, not "three" (the page then listed four). Dropped the "(three levels)" nesting limit — nothing in the code enforces a depth.
  • Dropped UPDATE from supported HTTP methods. It isn't an HTTP verb; the list was copied from python-http-client's ALLOWED_METHODS, which is defined but never enforced. Noted that the method is passed through unvalidated.
  • base_url / endpoint_path placeholders are filled from iteration columns only, not from user_parameters — the page said either would work, and contradicted itself two sections later. Also documented that a base_url placeholder resolves once and is then reused for every later row.
  • EMPTY_REQUEST sends one request without iterate_by_columns, not one per row. As written, a 100-row table meant to fire 100 webhooks fires one.
  • Iteration mode does not override chunk_size to 1; chunk_size still controls payload shape. Proven by docs/examples/005, whose recorded request is an array.
  • Dynamic functions also evaluate in headers and query_parameters, not only user_parameters.
  • json_mapping's nesting_delimiter / chunk_size / column_data_types are all required when the section is present.
  • Stale key names: request_optionsrequest_parameters (×2), column_typescolumn_data_types.datatype_override.
  • [[id]] is canonical; {{id}} is documented as a still-supported legacy alias (the code comment says so outright).
  • bool conversion also accepts 0 / "0" as False.

Plus: leaked Python tuple notation on retry_config.codes, address__streedaddress__street with its invalid JSON repaired, and a chunk_size sample that disagreed with both its prose and its own shown output.

3. Two examples could not have run

  • The Iterations and Customer.io examples both set Authorization: {"attr": "token_encoded"} while defining no such user parameter. That's a hard validation failure, so neither config worked. Removed (Customer.io already uses BasicHttp; Exponea and Slack legitimately define token_encoded and keep theirs).
  • The Customer.io example was additionally missing user_parameters entirely, which raises KeyError: 'user_parameters' — the component indexes rather than .gets it, and every functional example ships "user_parameters": {} even when empty. Added.

All 6 JSON blocks on the examples page now parse.

Also: Content-type: application/csvapplication/json where the body is JSON; Slack example debug: truefalse (the page's own CAUTION warns it prints payloads into the job log); stripped the trailing ? from all 4 endpoint_path values (a v1-converter artifact); and removed leaked @keboola.com addresses, including a real employee's, replacing them with the @test.com values from the input table.

4. Links and typos

#enpoint-path#endpoint-path; an empty [dynamic functions]() href; the slashless overview/encryption/ link; a missing trailing slash; "encripted" and 7 other inherited typos; and 3 sections that all described "default query parameters" regardless of their actual subject.

Rotted third-party links repointed: Exponea → Bloomreach Engagement, Customer.io → docs.customer.io/integrations/api/track/, and strftime.org (now a 403 vendor marketing page) → docs.python.org. ⚠️ Note documentation.bloomreach.com/engagement/reference/batch-commands is a soft 404 — HTTP 200 with a not-found body — so the real page is …/batch-commands-2, verified by content.

Verification

  • npm run build clean — 259 pages.
  • audit-phase2.mjs vs this branch's own pre-fix baseline: unclosed code fences 1 → 0, 0 missing images, 0 malformed tables, broken links unchanged at 6.
  • All 29 self-anchors resolve (was 5 dead). The rendered config map parses as valid JSON with all 5 top-level keys. All 3 /extend/generic-writer/* redirects resolve. One <h1> per page.

⚠️ Merge order

The 3 links to /components/extractors/generic-extractor/** in index.md are deliberate forward-refs to the Generic Extractor batch (#1054), which creates all three targets including the ## Generic Extractor Requirements heading and the tutorial/json/ page. Please merge #1054 before this PR, or those 3 links 404 on production.

Open question for you

autodetect: false may not actually work, and the page still claims it makes unspecified columns strings. The pinned converter (csv2json 0.5.7, hone_csv2json.py:73) hardcodes infer_undefined=True, discarding the flag the writer passes down — so type inference appears to always be on, and a reader setting autodetect: false to protect zip codes or phone numbers would still get numbers. That reads like a component bug, not a docs bug, so I left the text alone rather than assert it. Worth raising with kds-team.

Deliberately out of scope

No screenshots, no "Create a new configuration" intro, and no documenting the real-but-undocumented options (ApiKey / Login / OAuth20ClientCredentials auth, continue_on_failure, md5_encode, the {"time": …} placeholders, the JSON_URL_ENCODED chunk-size override). All recorded as follow-ups on PRDCT-553. Also filed there: the component's Developer Portal documentationUrl still points at developers.keboola.com/extend/generic-writer/configuration/ and needs repointing by a kds-team maintainer before the dev domain 301s.

Supersedes

Replaces the stacked #1032 (closed with the #1027 stack once the per-unit queue is drained).

🤖 Generated with Claude Code

Placement / dedup + regroup audit (2026-08-03)

Ran the placement/dedup pass (migration-placement skill). No duplication — there was no
existing Generic Writer page on main, so this is net-new. Placed first-class under Data
Destination Connectors (components/writers/generic-writer/), parallel to how Generic Extractor
was placed. Component id kds-team.wr-generic verified against the live catalog. No single-page
fix needed.

Regroup question for Jordan / Matias — Components ("use") vs Extending Keboola ("build")
[strong, spans several units]:

Generic Writer and Generic Extractor are build-your-own-connector tools, but they're filed on
the use side (under Components), while the build docs live in the separate top-level
Extending Keboola section — whose sub-node is also titled "Components". So there are two
nav nodes named "Components" and the build tools sit away from the build docs:

BEFORE (today)
  Components            (USE — ready connectors)
    ├─ Data Source Connectors      › … › Generic Extractor   ← build tool, on the use side
    └─ Data Destination Connectors › … › Generic Writer      ← build tool, on the use side
  Extending Keboola     (BUILD)
    ├─ Components        ← duplicate "Components" title
    ├─ Common Interface
    ├─ Job Queue
    └─ Publishing Component

OPTION A (recommended to consider) — keep the tools under Components for discoverability,
  and rename the build node to kill the title clash:
  Extending Keboola › "Components"  →  "Building Components"

OPTION B — move Generic Extractor + Generic Writer next to the build docs under Extending
  Keboola (they're build tools). Trade-off: users hunting for a connector won't find them
  among connectors.

Recommendation: these tools are used both as ready connectors and as build primitives → lean
Option A (keep under Components + rename the duplicate "Components" node). Owner/Matias call.
Related: the Generic Extractor home question on #1054 (first-class vs inside "Other") is the same
family of decision. Not touched here — surfacing per Jordan's "formulate the question, ask Matias."

@linear-code

linear-code Bot commented Jul 28, 2026

Copy link
Copy Markdown

PRDCT-553

@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
connection-docs Ready Ready Preview Aug 6, 2026 11:22pm

Request Review

Nikita and others added 2 commits August 5, 2026 01:42
Re-cut of phase-2 batch 3 (was #1032, stacked on #1027) as a standalone
per-unit PR off main, per the 2026-07-27 pivot.

Moves the 3 Generic Writer pages to /components/writers/generic-writer/
(with the other data destination connectors). Old /extend/generic-writer/*
URLs keep working via redirect_from.

Build clean; audit 0 missing images. Broken links are forward-refs to
/components/extractors/generic-extractor/ (batch PRDCT-552, not yet on main).

Supersedes the stacked #1032 (closed with the #1027 stack once the queue drains).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ified facts

Deep-review pass on the Generic Writer page set (Jordan, 2026-07-29): every
claim checked against a source of truth before re-requesting review.

Source of truth: component id kds-team.wr-generic, repo
bitbucket.org/kds_consulting_team/kds-team.wr-generic (public, live) —
src/configuration.py (schema), src/component.py (placeholders/iteration),
src/json_converter.py, src/user_functions.py, src/http_generic/auth.py, and
the recorded functional examples under docs/examples/001-037.

Rendering blocker (introduced by the phase-1 migration):
- The inlined writer-config-map include produced "```json {" / "} ```", which
  is not a valid CommonMark fence pair. The result was one 168-line code block
  swallowing lines 66-233, so "## Api", "### Base URL" and "### Retry Config"
  rendered as literal text and the #api / #base-url / #retry-config anchors
  did not exist. Headings 34 -> 37; longest code block 168 -> 84 lines.
- Removed the 46-line jQuery <script> + <style> inlined from
  writer-config-events.js. There is no jQuery in this repo, its
  span:contains() selectors targeted Jekyll/Rouge markup (this site uses
  Expressive Code), and 6 of its hardcoded anchors were wrong.
- Reworded the config-map lede, which promised a clickable map that the
  removed script used to provide.

Claims refuted by the component source:
- autodetect default is false, not true (ColumnDataTypes.autodetect = False).
- Four datatypes, not "three" (DataType enum); dropped the "(three levels)"
  nesting limit, which no code enforces.
- Dropped UPDATE from the supported methods: it is not an HTTP verb and the
  list was copied from python-http-client's never-enforced ALLOWED_METHODS.
  Noted that the method is passed through unvalidated.
- base_url / endpoint_path placeholders are filled from iteration columns
  only, not from user_parameters; documented that a base_url placeholder
  resolves once and is reused for later rows.
- EMPTY_REQUEST sends one request without iterate_by_columns, not one per row.
- Iteration mode does not override chunk_size to 1; chunk_size still controls
  payload shape (proven by docs/examples/005's recorded array request).
- Dynamic functions also evaluate in headers and query_parameters.
- json_mapping's nesting_delimiter / chunk_size / column_data_types are all
  required when the section is present.
- Stale key names: request_options -> request_parameters (x2),
  column_types -> column_data_types.datatype_override.
- [[id]] is canonical; {{id}} documented as a legacy alias.
- bool conversion also accepts 0 / "0" as False.
- retry_config codes: dropped leaked Python tuple notation.
- Fixed address__streed -> address__street and its invalid JSON.
- chunk_size sample 1 -> 2 to match the prose and the shown output.

Examples:
- Removed Authorization headers referencing an undefined token_encoded from
  the Iterations and Customer.io examples: an {"attr": ...} with no matching
  user parameter is a hard validation failure, so both configs could not run.
- Added the required "user_parameters": {} to the Customer.io example, which
  otherwise raises KeyError: 'user_parameters'. All 6 JSON blocks now parse.
- Content-type application/csv -> application/json where the body is JSON.
- Slack example debug: true -> false (it prints payloads into the job log).
- Stripped the trailing "?" from all 4 endpoint_path values (a v1 converter
  artifact).
- Replaced leaked @keboola.com addresses, including a real employee address,
  with the @test.com values from the input table.

Links, anchors and typos:
- #enpoint-path -> #endpoint-path; empty [dynamic functions]() href.
- Rotted third-party links: Exponea -> Bloomreach Engagement (note that
  .../reference/batch-commands is a soft 404, so .../batch-commands-2 is
  used), Customer.io -> docs.customer.io/integrations/api/track/,
  strftime.org (now a 403 vendor page) -> docs.python.org.
- index.md: relative overview/encryption/ link, which has no help target yet,
  now points at the live dev URL; trailing slash on the examples link;
  "encripted" and 7 other inherited typos; 3 sections that described "default
  query parameters" regardless of their actual subject.
- Cross-linked Generic Writer from the Writers hub and Other hub pages.

Verified: build clean (259 pages); audit-phase2 unclosed code fences 1 -> 0,
0 missing images, 0 malformed tables, broken links unchanged at 6 (the 3 from
these pages are the known forward-refs to the Generic Extractor batch, #1054);
all 29 self-anchors resolve; the rendered config map parses as valid JSON;
all 3 /extend/generic-writer/* redirects resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…riter-recut

# Conflicts:
#	src/content/docs/components/writers/other/index.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-docs-migration developers.keboola.com → help.keboola.com migration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant