Skip to content

docs(v3): document *.field.list, and state the camelCase rule once - #473

Merged
IgorShevchik merged 3 commits into
mainfrom
docs/v3-entity-fields
Sep 5, 2026
Merged

IgorShevchik merged 3 commits into
mainfrom
docs/v3-entity-fields

Conversation

@IgorShevchik

@IgorShevchik IgorShevchik commented Sep 5, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #466. Documentation only — no SDK change, as the issue asked.

The gap

*.field.list / *.field.get appeared nowhere in docs/, skills/ or packages/.
The only place a reader could reach it was a comment on a playground command — somebody
needed the method, used it, and the answer landed in a demo. It is 91 of 245 methods
on the measured cloud portal: 37% of the v3 surface.

What the docs pointed at instead was the OpenAPI document: the right answer to which
methods exist
, a heavy one to which fields does this entity have, and no answer at all
to filterable, editable and requiredGroups, which the request schema does not carry.

What lands

New page 8.discovering-entity-fields.md, numbered next to 7 because they are two halves
of one question; page 7 gained a pointer back.

Everything on it is measured first-hand. Six facts the issue listed as unverified or did
not have:

  • sortable and filterable are independent. This is the one worth the page. On
    main.eventlog they name the same five fields of thirteen — a coincidence that reads
    exactly like a rule. On tasks.task they diverge: title is sortable: true,
    filterable: false, and one field of ninety-five is filterable at all. A reader who
    checks one flag and assumes the other is wrong on the second entity they try.
  • <entity>.field.get answers with result.item — singular, not the result.items of
    .field.list. Assume symmetry and you get undefined.
  • select narrows the descriptor keys: select: ['name', 'sortable'] returns rows
    with exactly those two.
  • requiredGroups is null, not [], when nothing requires the field — iterate it and
    you throw. It reads ["add"] on tasks.task's title / creatorId / responsibleId,
    not the ["add","update"] the audit's reference recorded from the schema.
  • The same refusal guards filter, not only order. tasks.task.list filtered on
    title answers HTTP 400 with Filterable in validation[].field, exactly as ordering on
    a non-Sortable field does. That matters because filterable has no other source — which
    is why the playground comment had to call this family in the first place.
  • A field being returned says nothing about whether it may be sorted or filtered on:
    description is one of the thirteen main.eventlog.list gives back, and both flags are
    false.

Seven entities publish a .list with no .field.list — the four
crm.*.timeline.activity.email families, humanresources.access.permission,
humanresources.node.communication, rest.scope — where the issue knew of two on-premise.

The camelCase rule

Stated once, as a rule. It existed only as a per-method footnote — "most notably
tasks.task.list on v2" — while the code has encoded it as a default all along
(?? 'id' on v3, ?? 'ID' on v2). A reader told the rule predicts the next occurrence; a
reader given the footnote waits to be bitten by it. 108 descriptors across two entities,
not one uppercase initial.

Three lines taught it backwards and are corrected:

Where What it said Why it is wrong
99.examples/8.ai-assistant.md:47 "the deal lookup uses v3 (camelCase) fields" The deal lookup is crm.item.get via actions.v2.call.make — an example that disproves the claim it is used to teach
skills/b24jssdk-filtering/SKILL.md:164 "v3-style methods (crm.item.list)" v3 publishes no crm.item.* at all; crm.item.* is camelCase for reasons of its own
skills/b24jssdk-recipes/SKILL.md:130 "CRM v3-style methods" same

The two v3 cursorIdKey rows illustrated the parameter with a v2 shape on a v3 page,
and now state the rule instead. The v2 rows already name tasks.task.list correctly and
are untouched.

Drive-by, from the same file

skills/b24jssdk-filtering/SKILL.md:141 promised DtoFieldRequiredAttributeException for a
non-Sortable field. The wire carries BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION
— the specific class inherits it and gets no registry code of its own — with the
distinguishing detail in validation[].field. Matching on the message would fail anyway:
portals answer in the portal's language.

A prediction that held, recorded here because it is reusable

Widening the measuring webhook's scopes changed the OpenAPI document by zero methods —
245 before and after. #463's audit inferred "module-driven, not scope-driven" by comparing
two different webhooks; this is the same portal before and after, which is the stronger form
of the same claim. The committed snapshot therefore needs no refresh, and scripts/data/ is
untouched by this PR.

What is deliberately not here

No actions.v3.fieldList helper and no typed FieldDescriptor: it is an ordinary method
call.make already reaches, and a wrapper would re-import the per-portal knowledge 2.0.0
deleted with the allowlist. No field-name normaliser — the SDK must pass portal names
through unchanged or select echoes and filters break. The 91 method names are not
enumerated: the count is portal-specific (147 / 220 / 245 methods in total).

Checks

🤖 Generated with Claude Code

https://claude.ai/code/session_01F22e2ft66y7nuBJjzdThBr

`*.field.list` / `*.field.get` appeared **nowhere** in `docs/`, `skills/` or
`packages/`. The only place a reader could reach it was a comment on a
playground command -- somebody needed the method, used it, and the answer landed
in a demo. It is roughly a third of the v3 surface.

What the docs pointed at instead was the OpenAPI document: the right answer to
"which methods exist", a heavy one to "which fields does this entity have", and
no answer at all to `filterable`, `editable` and `requiredGroups`, which the
request schema does not carry.

New page `8.discovering-entity-fields.md`, numbered next to 7 because they are
two halves of one question. Page 7 gained a pointer back.

Everything on it was measured against a live portal rather than restated, and
three things the issue marked "not verified" now are:

- `<entity>.field.get` answers with `result.item` -- singular, not the
  `result.items` of `.field.list`. Worth a line of its own; a reader who assumes
  symmetry gets `undefined`.
- `select` narrows the *descriptor* keys: `select: ['name', 'sortable']` returns
  rows with those two.
- `requiredGroups` on `tasks.task` reads `["add"]` on `title`, `creatorId` and
  `responsibleId` -- not the `["add","update"]` the audit's reference recorded
  from the schema. The page says what the wire says.

And one fact the issue did not have: the same validation refusal guards
**`filter`**, not only `order`. `tasks.task.list` filtered on `title`
(`filterable: false`) answers HTTP 400 with `Filterable` named in
`validation[].field`, exactly as ordering on a non-`Sortable` field does. That
matters because `filterable` has no source but this family -- which is why the
playground comment had to call it in the first place.

The camelCase rule is now stated once, as a rule. It was present only as a
per-method footnote -- "most notably `tasks.task.list` on v2" -- while the code
has encoded it as a default all along (`?? 'id'` on v3, `?? 'ID'` on v2). A
reader who is told the rule predicts the next occurrence; a reader given the
footnote waits to be bitten by it. 108 descriptors across two entities, not one
uppercase name.

Three lines taught it backwards and are corrected. `99.examples/8.ai-assistant.md`
derived "camelCase means v3" from a **v2** call -- an example that disproves it.
The filtering and recipes skills called `crm.item.list` a "v3-style method" when
what they meant was that it is camelCase; v3 publishes no `crm.item.*` at all.
The two v3 `cursorIdKey` rows illustrated the parameter with a v2 shape on a v3
page, and now state the rule instead. The **v2** rows are correct and untouched.

Drive-by from the same file: the filtering skill promised
`DtoFieldRequiredAttributeException` for a non-`Sortable` field. The wire carries
`BITRIX_REST_V3_EXCEPTION_VALIDATION_REQUESTVALIDATIONEXCEPTION` -- the specific
class inherits it and gets no code of its own -- with the distinguishing detail
in `validation[].field`. Matching on the message would fail anyway: portals
answer in the portal's language.

No SDK change, as the issue asked. No `fieldList` helper: it is an ordinary
method `call.make` already reaches, and a wrapper would re-import the per-portal
knowledge 2.0.0 deleted with the allowlist.

Closes #466
Refs #113, #185

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F22e2ft66y7nuBJjzdThBr
…llow each other

The webhook gained the scopes it was missing, so the one thing this page took on
trust is now first-hand: `main.eventlog.field.list` answers 13 descriptors under
`result.items`, named exactly as the audit recorded, none of the 108 across the
two entities starting with an uppercase letter; and `main.eventlog.list` ordered
by `description` answers HTTP 400 naming `EventLogDto` and `Sortable`. The "not
verified" note comes off.

Measuring it turned up the thing most worth saying on the page, which no single
entity shows. On `main.eventlog`, `sortable` and `filterable` name the same five
fields of thirteen -- a coincidence that reads exactly like a rule. On
`tasks.task` they diverge: `title` is sortable and not filterable, and one field
of ninety-five is filterable at all. So the flags are independent, and a reader
who checks one and assumes the other is wrong on the second entity they try. Now
a warning, with both measurements.

Two smaller corrections from the same run. `requiredGroups` is `null` rather than
an empty array when nothing requires the field -- iterate it and you throw. And a
field being *returned* says nothing about whether it may be sorted or filtered
on: `description` is one of the thirteen `main.eventlog.list` gives back.

The counts are mine now instead of approximate: 91 of 245 methods on the measured
cloud portal are `*.field.*`, 37%, with the per-module split; and seven entities
publish a `.list` with no `.field.list` -- the four `crm.*.timeline.activity.email`
families among them -- where the issue knew of two on-premise.

Separately, and worth recording because it was a prediction rather than an
observation: widening this webhook's scopes changed the OpenAPI document by
**zero** methods, 245 before and after. The audit inferred "module-driven, not
scope-driven" by comparing two webhooks; this is the same portal before and
after, which is the stronger form of the same claim. The committed snapshot
therefore does not need refreshing, and `scripts/data/` is untouched.

Refs #466, #463

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F22e2ft66y7nuBJjzdThBr
Two additions, both from the maintainer's reading of the same measurement.

The flag is the source of truth, and which fields carry it is decided by the
Bitrix24 module that owns the entity -- so the set changes from one module
version to the next. Code that reads the flag keeps working across a portal
upgrade; code that hard-codes today's answer does not. Said on the page, next to
the numbers it governs.

And the contrast that makes the numbers legible rather than alarming: a rich
`order` beside a bare `filter` is a normal state for a v3 entity. `tasks.task`
marks nineteen fields sortable and one filterable; the same entity on
`restApi:v2` filters on `RESPONSIBLE_ID`, `STATUS` and `GROUP_ID` without
complaint. That is a difference between the two APIs, not a fault to work
around.

A correction I owe the record: an earlier draft of this reasoning held that the
reference documentation promised filtering the module does not deliver. It does
not. The MCP docs tool answered with a merged v2/v3 record pointing at
`rest-v3/tasks/tasks-task-list.html`, which omits the restriction; the actual v3
page, `tasks/tasks-task-list-rest-v3.html`, states that `id` is the only
supported filter. The documentation was right and my source was wrong, so the
page now cites it rather than contradicting it.

Refs #466

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F22e2ft66y7nuBJjzdThBr
@IgorShevchik
IgorShevchik merged commit 9a70742 into main Sep 5, 2026
10 checks passed
IgorShevchik added a commit that referenced this pull request Sep 5, 2026
…t guide (#474)

Follow-up to #473, which added the "Discovering entity fields" guide but wired
it only into the b24jssdk-rest skill — so the two skills where the question
actually comes up had no way to reach it.

One pointer each: b24jssdk-filtering (why a `filterable: false` field is
refused rather than ignored), b24jssdk-recipes (folded into the sentence that
already states the camelCase rule), and b24jssdk-rest next to the existing
"Discovering v3 methods" link.

Documentation only; no runtime change.
@IgorShevchik
IgorShevchik deleted the docs/v3-entity-fields branch September 6, 2026 03:33
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.

docs(v3): document the *.field.list metadata family and the v3 camelCase field-name rule

2 participants