feat(agent-bff): synthesize capabilities for legacy lianas - #1893
Conversation
3 new issues
|
b7fce47 to
d607cbc
Compare
3be7bf2 to
990d725
Compare
d607cbc to
eb3f9cf
Compare
403641b to
817e759
Compare
817e759 to
8760afb
Compare
990d725 to
64e7bf7
Compare
fb639f5 to
7fb2459
Compare
nbouliol
left a comment
There was a problem hiding this comment.
Spec: no Linear ticket is linked on this PR, so the functional check was limited to the PR description. The change matches it.
Applies to: the PR as a whole
Claude Opus 5 (claude-opus-5): Should fix: no ADR records that the BFF decides an agent's capabilities from the liana name it self-reports.
Code
agent-capabilities-fetcher.ts:67 reads meta.liana from a cached schema and treats three self-reported names as a capability set.
A way out: run /adr and record the decision against the capability negotiation it replaced.
Reproduction
- Read docs/adr in agent-nodejs.
- It holds one ADR, about case-insensitive decisions.
- Search the org ADR corpus for capabilities, schema, liana, operators and filter.
- None covers this decision.
- Read the diff, which adds no ADR file.
…ithMeta Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXZTKo9YNJS6HNQevQ4LUJ
7fb2459 to
c34380e
Compare
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXZTKo9YNJS6HNQevQ4LUJ
|
Reopened: no ADR records deciding an agent's capabilities from the liana name it self-reports. How it was checkedPredicate: an accepted ADR covering the decision to read
No reply addressed the finding, so the rationale still lives only in file comments. |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXZTKo9YNJS6HNQevQ4LUJ
|
Closed: an accepted ADR now records deciding a v1 agent's capabilities from the liana name the schema carries. How it was checkedPredicate: an accepted ADR covering the decision to read The ADR added in Nothing pins a decision record, so the ADR file itself is where the absence is accounted for. |
nbouliol
left a comment
There was a problem hiding this comment.
Four findings raised, four closed: the sort enum no longer advertises a sort the runtime refuses, an array column publishes no operator, a non-enumerated aggregator is a 400 before any agent call, and the liana-name decision is recorded in an accepted ADR. Three carry a regression test that fails on the pre-fix code.
Two nits left deliberately unaddressed, neither worth holding this up: schemas.ts:521 still describes details as { field } on unknown_field and field_not_filterable only, though field_not_sortable carries one too, and SchemaCache.meta has no production caller since getPayload() replaced it.
LLM Integration Tests (ai-proxy) is red but failed identically before the fixes and this PR touches no ai-proxy file. Merge order still stands: #1894, then #1895.
53cdab3
into
fix/agent-bff-derive-primary-key

Top of a three-PR stack: #1894 then #1895 merge first, and this one carries the last three commits. Review those three; the parents' diffs belong to their own PRs.
What
The BFF serves constrained reads — filter, sort, projection — in front of a v1 liana (
forest-express-sequelize,forest-express-mongoose,forest-rails). It decides from the liana the schema announces.BFF_LEGACY_CAPABILITIESis gone.Why
v1 lianas never served
POST /forest/_internal/capabilities. Every constrained read died on that 404 and the collection was unusable. The first shape of this feature asked the operator to declare the generation with a flag, for information the BFF already receives in the schema'smeta.liana.How
forestadmin-clientstops dropping the schema'smeta, so the liana name reaches the BFF. On a 404 from the capabilities route, the fetcher matchesmeta.lianaagainst the three legacy names and synthesizes from the apimap: the operator set that liana implements per column type, plus the fields the schema marks filterable and sortable. Any other liana keeps throwing.includes_allis not published. Measured on a scalar column it answers 500 with a leaking SQL fragment in Express and 422 in Rails, so advertising it would advertise a crash.The third commit is a refactor the synthesis needs: three implementations converted a PascalCase condition tree to the snake_case the wire expects, each with its own idea of what to do with an operand-less leaf. They agreed on all 43 operators when measured, which is luck, not a contract. The walk now lives in one exported place.
Scope and safety
No agent code changes, v1 or v2. Nothing in the wire format is new to either generation: v2 already parses snake_case operators and accepts
value: nullon operand-less leaves.SchemaFetchernow returns{ collections, meta }instead of a bare array. The in-process dispatcher added by #1876 is the one other consumer and its test follows the new shape.How to test
yarn workspace @forestadmin/agent-bff test— 1822 tests, 95 suites. Also measured on five running agents:forest-express-sequelize,forest-express-mongoose,forest-rails, a v2 node agent and a v2 ruby agent, with the capabilities route absent on the three v1 ones. Constrained reads answer 200 on all five. A cold OpenAPI unfold is pinned on a 269-collection schema, the largest measured on the fleet.Definition of Done
General
Security