[oschema generator] service-block method after a section comment inherits the next method's description (off-by-one) #153
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_lib#153
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The
openrpc_server!/ oschema->OpenRPC generator mis-assigns method descriptions by one when aservice-block method is declared immediately after a section comment: the method inherits the next method's description.Evidence (hero_planner):
90_rpc.oschemais correct —ping() -> bool # liveness check; returns true if the server is responsiveandsystem_health() -> str # returns "ok"; .... But the regeneratedopenrpc_main.jsondocumentspingwith system_health's text ('returns "ok"...') andsystem_countswith ping's text ('liveness check...'). The SDK client doc-comments are fine — only the OpenRPC JSON (which drives the API Docs pane) is shifted. The shift is localized to the system block wherepingwas inserted after a comment line.Fix at the generator (do NOT hand-edit the generated json): the oschema parser should not let a leading section comment cause a description off-by-one. Interim workaround: add a blank line / reorder so a method isn't directly after a section comment, then a clean regen re-aligns (verify
pingshows 'liveness check…' in/api-docs-pane).Cross-cutting: any migrated service with a commented service block can hit this — worth checking hero_collab during its migration. Found via hero_planner.
Triage (verified on-box) — difficulty: S, breaking: no
Root cause located.
parse_rpc_method(crates/oschema/src/oschema/parser.rs:703/716/723) callsskip_comments()after parsing the return type / error clause /@ssebut beforecollect_trailing_comment()(line 727).skip_commentspushes every contiguous comment — including the method's own same-line trailing# description— intopending_commentsas a leading comment, so the next method claims it viatake_leading_comments(). Classic off-by-one. The struct/field and union parsers already guard against exactly this (parser.rs:961/:1197).Fix (~3–9 lines, 1 file, no API change): collect the trailing comment into
method.commentsbefore each post-clauseskip_comments(), mirroring the field/union parsers. Do not hand-edit the generated JSON — the parser fix regenerates correct output on the next build.Verified on-box: applied → oschema lib 269 + integ 59, macros
openrpc_server_test7 +openrpc_from_oschema_test8 all pass; the shift disappears (e.g. plannerpingstops showingsystem_health's text).Not breaking: rebuilt
hero_planner_serveragainst the fixed generator — compiles; regeneratedopenrpc_main.jsonchanged only thedescriptionfield (14 methods corrected), method names/params/results/components byte-identical. SDK docs derive fromsummary(= method name), notdescription, so SDKs regenerate identical. Each consumer picks it up on its nexthero_libbump; no coordinated cut needed.Reach: ~50 repos have
.oschemaservice blocks; 7 carry the literal trigger shape today (hero_planner, hero_proc, hero_osis, hero_ledger, hero_sync_webdav, zinit_archive, mycelium_portal_archived).Residual (separate, cosmetic): a leading section-banner comment (e.g.
── system ──) still attaches to the first method after it — that's normal leading-comment behavior, not this off-by-one. Optional follow-up viamarkers.rs::is_marker_only_comment.Fixed on
development(squash-merged).Root cause:
skip_comments(inparse_rpc_method,parse_union_type, and the bare-@ssepath ofparse_sse_annotation) converted a method/enum same-line trailing comment into a leading comment for the next node — shifting every description by one.Fix: added
skip_comments_preserving_trailing()and used it at every clause/variant boundary so the owning node collects its own trailing comment viacollect_trailing_comment(mirrorsparse_field). The logic delta is ~1 helper + swapping ~7 boundary skip-calls + removing one now-redundant collect; the remaining ~111 of 121 added lines are regression tests. No parsing-structure/AST change.Verified: RED→GREEN with 2 regression tests (return/error/void/
@ssemethods + typed enums);herolib_oschemalib 270/0, integration 59/0. A/B regen of planner's real schema (pristine parser vs fixed parser, same hero_lib otherwise) changed onlydescriptionfields — 28 corrected; method names/params/results/components byte-identical (e.g.pingnow reads its own "liveness check…" instead ofsystem_health's text).Residual (separate, pre-existing cosmetic): the decorative
── section ──banner still prefixes the first method of each section. Tracked as a follow-up viamarkers.rs::is_marker_only_comment— not part of this off-by-one.