Client API reference, a decision-first install journey, and walkthrough steps 11–12 - #177
Merged
Merged
Conversation
The sixth gate arrived with dc7c799 and was written into AGENTS.md and the check chain, but the README kept counting five — so the file most people read first described a smaller CI than the one their pull request has to pass, and the one gate it left out is the one that fails without anybody touching this repository. Count six, and name check:api-names in the list so the prose matches package.json again. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
Every abap2UI5 app is written against one interface - z2ui5_if_client, handed
to the app as `client` on every roundtrip - and no page anywhere listed it.
The interface carries nearly two hundred ABAP-Doc lines on its methods,
parameters and constants, and the only way to read any of it was to open the
source file; a reader asking "what can client-> do" reversed the answer out of
cookbook examples, and an agent fell back on training data.
So the reference is GENERATED, the way the Working Samples blocks are, because
a hand-written API page is wrong the release after it is written:
scripts/generate-api-reference.mjs parses the interface at the release the
site names - methods with parameter types, defaults and preferred
parameters, the cs_* constant structures with their values and run
labels, the types, and the ABAP-Doc on all of them - and writes two
committed artefacts:
docs/resources/api.md the page, between api:start/end markers
like every other generated block; the intro around them is hand-written.
Methods are grouped by the interface's own prefixes (view_*, nest*,
popup_*/popover_*, _bind*, message_*, ...), obsolete methods carry a
badge derived from their own doc. In the sidebar under Resources, which
also puts it into the generated llms.txt automatically.
docs/public/api/client-api.json the same model as one JSON document, so
AI tooling fetches one URL instead of parsing a page. Committed, unlike
llms.txt: it is a claim about another repository at a pinned release,
not a projection of the pages next to it - the samples-block case.
check:api-reference is the freshness gate - regenerate and compare, fail on a
difference, SKIP honestly when github.com is unreachable - wired into npm run
check, check.yml and deploy.yml the way the other six are, making it seven.
The acquisition moved into scripts/lib/client-interface.mjs, shared with
check-api-names so the two gates cannot drift on where the truth comes from.
And the generated page caught a real gap in that gate on its first run:
`cs_device-system-phone` - the full path exactly as an app spells it - was
rejected, because the parser never registered a nested group (`system`) as a
member of its parent, despite its own comment claiming that spelling resolves.
It does now.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
The three machine-readable artefacts - llms.txt, llms-full.txt, the per-page markdown - are generated at build time and gitignored, and that stays right: they are a projection of the pages next to them, so the only correct copy is the one the build just made, and a committed copy would be stale on every commit that touches a page. But it leaves a blind spot this repository itself documents caring about: the agent that lands in a CHECKOUT rather than on the site finds neither file and has no way to learn they exist. So the root gets a committed llms.txt that is a pointer and nothing else - the published URLs of the generated files and of client-api.json, plus one line on where the sources live. It is maintained by hand because it names URLs, not content, and it needs no freshness gate for the same reason. Committing the generated files instead was considered and rejected in AGENTS.md, where the distinction between a projection (build-time, gitignored) and a claim about another repository (committed, gated) was already the rule. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
…y step Two no-system paths existed - the playground behind every Run button and the transpiled live demo - but the page opened mid-install, with the live demo in a tip and the playground nowhere. Now the reader meets one decision before any step: try it in the browser, explore the live demo, or install on your own system - and only the third continues down the page. The install itself becomes an end-to-end journey: pull a release rather than main, know that the endpoint serves the frontend itself (with the four delivery branches of abap2UI5/frontend named for the scenarios that do deploy one), learn ?app_start= as the URL form everything else uses, and finish on an explicit Verify step - what you should see, and for each wrong outcome the place that explains it, from an inactive SICF node to the framework's own "The app '...' does not exist in the system." The VS Code extension's "Check System Connection" command is named there as the step-by-step diagnosis, and the extension page now documents that command where the launch URL is explained. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
The page explained ten failures by behavior - nothing renders, data does not update - which helps when you know what you did. When all you have is a literal error text, you need the other direction. The new index maps each message to its cause and fix: the framework's own raised texts (the binding errors, APP_SERIALIZATION_ERROR, the dispatch limit, the app that "does not exist in the system"), the browser-side ones (failed module loads, the empty string no UI5 enum accepts, the CSP EvalError, ICFEUCONFORBIDDEN), the abapGit import that leaves an empty class stub behind, and the icon that disappears without a word. Every text was verified against the framework source or a documented real case - none invented. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
Step 10 refactored the invoice app and stopped; transport, security and testing existed only as configuration pages nothing guided you through. Two steps finish the arc. Step 11, From Playground to Production, takes the finished app to a real system by walking the existing chapters in journey order - the two data seams become real SQL, the framework gets pinned to a release, the transport goes bottom-up so a failure names its layer, authorization is placed at the service and in the app, and users get the ?app_start= URL as tile or bookmark - the chapters keep the details, the step provides the order. Step 12 collects what Step 10's structure promised: the data methods are plain ABAP, so the test class is ordinary ABAP Unit - DEFERRED, LOCAL FRIENDS (an activation error when missing, not a style issue), three tests through the same public attributes the view binds. Its app class is Step 10's, reprinted so the step stands alone and stays under check:examples; the test include was compiled against 1.143.0 with the same abaplint setup the gate uses. Overview, sidebar and the two step-count sentences follow, and the AGENTS.md button ledger records the reprinted class: 61 complete classes, 39 with a button. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
The samples repositories run on a distillation rule - every fix found by hand becomes a rule, a reference example or a gate, so nobody discovers it twice. The contribution page now says the reader-facing half of the same discipline: a question answered twice on Slack or in an issue wants to become a Common Failures entry, a paragraph on the page that should have answered it, or a check. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
…out is The figures in llms.txt were counted from sibling checkouts and silently left out when none was at hand - and a checkout step that is continue-on-error, or a workflow with no sample repository at all, is exactly the build that publishes the copy agents actually fetch. So the published file could carry no corpus sizes while every local build showed them. Each sample repository now commits the same catalogue as one JSON document, catalogue.json at its root. countCatalogue walks a chain, first answer wins: the checkout's catalogue.json, the checkout's SAMPLES.md through the parser the sample links go through, the catalogue.json the repository publishes on its default branch (fetched), then no number. The two catalogue.json steps read the same file, so a build with a checkout and a build without one publish the same figure - which is also why, inside a checkout, catalogue.json outranks the SAMPLES.md parse: in samples the two genuinely differ (SAMPLES.md also lists the src/00 system area and the helpers; catalogue.json scopes itself to the portable src/01 set), and the repository's own claim about itself is the one figure both paths can agree on. The samples figure therefore reads 97 now, not 150, on both paths. The discipline survives the new source: every step counts entries - a class name plus a file pointer, the JSON shape of the row the SAMPLES.md parser accepts - and never repeats a counts field, whose fixtures here deliberately lie to prove it. The fetch may 404 (the file is not on main until the sibling PRs merge), time out or find no network; each failure costs the figure and never the build. generate-llms.mjs counts once per repository and logs which source answered, so a figure that arrived from the fallback when a checkout was expected is visible in the run output. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
The dispatcher skeleton on the life-cycle page declared render_main and on_post and implemented neither, so the most-copied pattern in the cookbook was a class that does not activate in any system — and the one complete app example on the page the Run button could never reach, because the playground rules rightly refuse a class that does not compile as printed. Implementing the two methods costs 27 lines and buys three things: the example now compiles under check:examples like every other view-building class, the page demonstrates the "one render method per view" rule it preaches instead of only naming it, and the fence gets its Run button. Verified in a served playground build end to end: the app starts, the view renders, and typing into the input and pressing Post produces "POST received: <the typed value>" — the whole lifecycle the page is about, watched working. The fixture pinning the declared-and-never-implemented shape stays; its comment now records that the page it was watched failing on has been completed, rather than pointing readers at a defect that no longer exists. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
… it so The playground rules fail towards no button, which is right for the reader and wrong for the maintainer: an example nobody ever measured looks exactly like an example that can never run. The ledger keeping those apart lived as two numbers in AGENTS.md — "61 app classes, 39 with a button" — and had already drifted to 68 and 46 without a word changing, because prose is where bookkeeping goes to go stale. Measured first: of the 21 buttonless complete app classes (after the life-cycle page was completed), every one is buttonless for a reason a browser cannot fix — VBAK, SFLIGHT, SCARR and KNA1 SELECTs, EML against CDS entities, ENQUEUE function modules, cl_bcs_message and cl_demo_output, a DDIC lookup, a class-local class, an add-on interface, and one authority check that deliberately shows nothing. So the exclusions become explicit. Each of the 21 now carries a marker directly above its fence — <!-- playground: no Run button — SELECTs from VBAK, which no browser database has --> — and check:playground, the eighth gate, refuses a complete app class with neither button nor marker, a marker above an example that HAS a button, and a marker attached to nothing, so intent can neither be omitted nor outlive a fix. --list prints every exclusion with both reasons, which is the worklist for the next real measurement. scripts/lib/playground-coverage.mjs holds the audit, test/playground-coverage.test.mjs pins one fixture per verdict, and check.yml and deploy.yml run the gate so it exists for pull requests, not just for whoever reads package.json. What stays hand-measured is stated rather than implied: whether a BUTTONED example actually starts, which only a playground answers. Six were driven in a served build this round — the newly buttoned life-cycle class through its whole event roundtrip, quickstart, About, Step 12, the tables page and the t100 SELECT — and all six started and rendered. AGENTS.md's ledger now carries the measured figures the gate reprints on every run: 68 app classes, 47 with a button, 21 excluded on purpose. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
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.
Seven commits closing the site's largest gaps for both audiences:
Infrastructure
docs/resources/api.md(sidebar: Resources → Client API) plus a fetchabledocs/public/api/client-api.json, both generated fromz2ui5_if_clientat the pinned release (37 methods with parameters/defaults/ABAP-Doc,cs_*constant structures, obsolete badges). Acquisition/parsing shared withcheck-api-names.mjsso the two gates cannot drift. Wired as the seventh check (check:api-reference) innpm run check,check.ymlanddeploy.yml;llms.txtpicks the page up automatically from the sidebar. The new parser also exposed and fixed a real bug incheck-api-names.mjs: nested constant group names likecs_device-system-phonewere wrongly rejected (1543 → 1628 validated names).llms.txtpointer — a clone previously contained no AI index at all (generated ones are gitignored). The pointer names the published URLs (llms.txt, llms-full.txt, per-page .md, client-api.json); rationale for not committing the generated files documented in AGENTS.md.Content
frontenddelivery branches explained (and why the basic install needs none), HTTP handler, first?app_start=call, and an explicit Verify step with the framework's literal error text and the VS Code extension's new "Check System Connection" command as the diagnosis tool.DEFERRED/LOCAL FRIENDSABAP Unit include, compiled separately against 1.143.0 with the gate's exact abaplint setup).All seven checks green before each commit (53 app-class examples compiled, 1669 API names validated). Part of an ecosystem-wide pass; no cross-repo merge dependency.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WLKJKRzJ6gYAM6i9Bjyt45
Generated by Claude Code