Conversation
…ry hint
Brings the portable pieces of mini's feat/main-session-work onto dev:
- context.go: Context.Metadata field — alias for Data, references the same
underlying map. Both fields interchangeable at read/write sites.
- responsive.go: responsiveVariant gains an optional media field for CSS
media-query hints (e.g. "(min-width: 1024px)"); new Responsive.Add(name,
layout, media...) method. Existing Variant(name, layout) becomes a thin
alias over Add.
- go.mod: drop stale dappco.re/go/core/{inference,log} indirect requires
(refreshed by go mod tidy — forge.lthn.ai/core/{go-inference,go-log}).
Mini's local deps/go-i18n/reversal grammar-vector rewrite does not apply to
dev: dev consumes reversal as an external package (dappco.re/go/core/i18n/reversal)
rather than an internal fork. That portion of the branch is left on
feat/main-session-work for future re-integration.
Verified: GOWORK=off go build ./... + go test ./... passes.
Co-Authored-By: Virgil <virgil@lethean.io>
… size guard-rails - cmd/codegen/main.go: drop "errors" stdlib import, use core.Is per Core convention (non-WASM path). - layout.go, path.go, responsive.go: add header notes documenting why these files use stdlib (errors/strings/strconv) instead of core — RFC §7 caps WASM at 3.5 MB raw / 1 MB gzip, and dappco.re/go/core transitively pulls fmt/os/log. - README.md, docs/index.md: migrate stale forge.lthn.ai/core/go-html module path to canonical dappco.re/go/core/html; refresh dependency diagram and Go version. All spec features are already implemented; this is spec-parity maintenance. Verified: go build ./..., go vet ./..., go test ./... all green (WASM size test back to 2.12 MB raw / 630 KB gzip after short-lived core-import regression). Co-Authored-By: Virgil <virgil@lethean.io>
Text() count/pluralisation now reads from either Context.Data or Context.Metadata, matching the alias contract when callers populate only one field.\n\nCo-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Make root-level duplicate slot IDs use stable per-slot numbering. Add a regression test for root duplicate block IDs. Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Broaden valid custom element names to match the HTML standard, add JS/TS string escaping for generated output, and cover dotted plus Unicode tag names in tests. Co-Authored-By: Virgil <virgil@lethean.io>
Preserve empty string slot values in renderToString so explicit empty slots still render as empty containers.\n\nCo-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Virgil <virgil@lethean.io>
Removes testify + indirect deps from go.mod/go.sum; rewrites assert/require calls in cmd/codegen/main_test.go, cmd/wasm/ register_test.go + size_test.go, and codegen/codegen_test.go to stdlib t.Fatalf patterns. go vet + go test all clean. Closes tasks.lthn.sh/view.php?id=729 Co-authored-by: Codex <noreply@openai.com> Via-codex-lane: Brontes-729 dispatch (fell back to cloud codex — local Lemmy lacks tool-call support)
Renamed module from dappco.re/go/core/html → dappco.re/go/html per
RFC, aligning with all other graduated Go repos which use dappco.re/
go/{name}. The embedded "core" in the old path collided conceptually
with the CoreGO root package (dappco.re/go/core).
Updated go.mod and 3 cmd/* files with the new import path. Doc/spec
references outside the allowlist remain and can be swept separately.
Verification: GOWORK=off go build ./... passes; no stale path left in
any *.go.
Closes tasks.lthn.sh/view.php?id=277
Co-authored-by: Codex <noreply@openai.com>
Neither file is WASM-linked so the reflect exception in layout.go/ responsive.go (RFC §11) does not apply. context.go: - Replaced reflect.TypeOf(svc) translator detection with an AvailableLanguages() interface path - Replaced reflect.ValueOf(a).Pointer() map pointer identity with a temporary sentinel alias probe node.go: - Replaced reflect-based typed-nil detection with explicit type-switch - Added generic isNilHTMLNode() marker on eachNode[T] Dropped reflect import in both files. Verification: go vet + go test -short ./... pass. Closes tasks.lthn.sh/view.php?id=275 Co-authored-by: Codex <noreply@openai.com>
Added `// Note:` annotations on html (html.EscapeString for text node rendering) and strconv (attribute numeric parsing) imports in node.go. Both are WASM-exempt — go-html keeps its WASM binary under the 3.5MB budget, so core.* helpers would add binary weight. reflect was already purged in f2ad72b (#275); context.go has no html/strconv to annotate. Closes tasks.lthn.sh/view.php?id=730 Co-authored-by: Codex <noreply@openai.com>
Module line was already dappco.re/go/html (migrated in #277). Updated
14 *.go files + go.mod require entries: dappco.re/go/core/{name} →
dappco.re/go/{name}.
Pre-existing module proxy gap (dappco.re/go/i18n@v0.2.1 404) is
unrelated — separate ticket.
Closes tasks.lthn.sh/view.php?id=728
Co-authored-by: Codex <noreply@openai.com>
Replaced forge.lthn.ai/core/go-inference → dappco.re/go/inference. Removed stale forge.lthn.ai/core/go-log (dappco.re/go/log already a direct require). Closes tasks.lthn.sh/view.php?id=371 Co-authored-by: Codex <noreply@openai.com>
- Migrate any forge.lthn.ai/core/* and dappco.re/go/core/* paths in go.mod and .go imports to canonical dappco.re/go/* form - Bump dappco.re/go/* deps (i18n, io, log, process, etc) to v0.8.0-alpha.1 - Add tests/cli/html/Taskfile.yaml AX-10 scaffold (build/vet/test under default deps), per RFC-CORE-008-AGENT-EXPERIENCE.md §10 - go-html is library + cmd/codegen + cmd/wasm; build target validates all Closes tasks.lthn.sh/view.php?id=278 Co-Authored-By: Athena <athena@lthn.ai>
…in.go (#614) - Removed flag + os + os/signal direct imports - Flag parsing → core CLI command registration via c.Command / c.Cli() - Errors propagated back to main - /dev/stdout open replaced with fd writes for sandbox compat - Watch mode uses Core context + Core signal action hooks Build + race tests PASS (with cache redirect). Co-authored-by: Codex <noreply@openai.com> Closes tasks.lthn.sh/view.php?id=614
… + responsive text_translate_args.go: strings.HasPrefix → core.HasPrefix, strings.Trim → core.Trim. responsive.go: removed strings, escapeCSSString uses local newTextBuilder() preserving uppercase CSS hex escaping. Co-authored-by: Codex <noreply@openai.com>
Removed errors import. Replaced errors.New with local sentinel error type for ErrInvalidLayoutVariant (keeps exported var as error type). Co-authored-by: Codex <noreply@openai.com>
Adds AX-6 exception boundary comments to context.go, node.go, render.go explaining that these files are WASM-linked and intentionally cannot import dappco.re/go/core (3.5MB raw / 1MB gzip WASM size budget per RFC §7). Reverts text_translate_args.go to use bare strings.* (correct for the WASM-linked path) since the earlier core.* sweep was incorrect for files in the WASM compile group. Co-authored-by: Codex <noreply@openai.com> Closes tasks.lthn.sh/view.php?id=372
Preflight (codex) found no docs/RFC.md in this repo and no dangling RFC.models.md reference in docs/index.md or anywhere else. Go source has types like Node, Layout, Responsive, Context — no substantive Model-named type/module that would warrant a separate sub-spec. Ticket presumed-stale or filed against a sibling repo. Closing as no-op for go-html. Co-authored-by: Cladius <cladius@lthn.ai> Closes tasks.lthn.sh/view.php?id=615
… documented Preflight (codex) found docs/architecture.md already has the "## mlxlm Subprocess Backend" section at line 260. Documents: - The "mlx_lm" backend - Embedded bridge.py - JSON Lines stdin/stdout contract - CGO-free use case - Import/load example - Limitations - nomlxlm build tag for backend removal Stale-fixed by prior architecture.md work. Closing as no-op. Co-authored-by: Cladius <cladius@lthn.ai> Closes tasks.lthn.sh/view.php?id=1026
Pass-2 sampling — pass 1 aliased "io" as goio rather than removing it (failed the explicit "io alias removed" done-criterion). This pass: - Drops flag, io, os, os/signal entirely - Replaces io.ReadAll/io.WriteString with coreio.Local.Read/Write - /dev/stdin and /dev/stdout for stdin/stdout piping (no syscall fallback) - Watch mode uses c.Context() shutdown lifecycle from core.Run - main returns errors via core runner — no os.Exit / syscall.Exit Final imports: context, time, dappco.re/go/core, dappco.re/go/html/codegen, dappco.re/go/io, dappco.re/go/log. Co-authored-by: Codex <noreply@openai.com> Closes tasks.lthn.sh/view.php?id=276
Per RFC §4-§8 + #731: PHP/server-side use cases (template rendering for emails, CMS export) need POST /v1/html/render. Browser/PWA use cases (client-side rendering without server round-trip) need WASM build with renderToString(template, data) → html. Lands the standard provider Service Framework + WASM target: * pkg/api/provider.go — HTMLProvider implementing api.Provider * pkg/api/handlers.go — POST /v1/html/render + POST /v1/html/grammar/check. Returns 501 with TODO(#731) for data-bound template rendering. * AX-10 tests: provider Good/Bad/Ugly + httptest Good/Bad per route * cmd/wasm/main.go — extended with renderToString(template, data) signature; legacy layout call path preserved for back-compat * Taskfile.yaml — `task wasm:build` runs GOOS=js GOARCH=wasm go build -o dist/render.wasm ./cmd/wasm/ Stdlib WASM by default; tinygo as a documented follow-up if size matters. dist/render.wasm produced at 2.2 MB on smoke build. Provider mounting in core/api Engine left to follow-up. go test ./... + go build ./... + task wasm:build all pass. Co-authored-by: Codex <noreply@openai.com> Closes tasks.lthn.sh/view.php?id=1019
…ker (#731 §6) Adds entitled.go with EntitlementChecker interface, denyAll default, emptyNode sentinel, and Entitled(args ...any) Node entry point that supports both: - Legacy Entitled(feature string, node Node) — context.Entitlements path - New Entitled(checker EntitlementChecker, feature string, node Node) — explicit checker path AX-10 Good/Bad/Ugly tests cover granted-checker, denied-checker, and nil-checker (defaults to deny). Codex note: node.go required removal of the old Entitled() function declaration to avoid name collision — variadic shim in entitled.go preserves existing callers. Closes tasks.lthn.sh/view.php?id=731 (§6 only — §4/§5/§8 are separate lanes) Co-authored-by: Codex <noreply@openai.com>
…ission (#731 §5) ShadowComponent type with RenderClass(), Register(), RenderAll(). Closed Shadow DOM by default, Mode "open" supported. Template content rendered via existing Node.Render() at Go codegen time — emitted JS uses a static string literal so the shadow root receives pre-rendered HTML, no runtime concat that could accept untrusted input. Local pascalCase + kebabCase helpers (with tests), including leading/trailing dash normalisation. AX-10 Good/Bad/Ugly tests pass via isolated GOWORK=off + temp GOPATH. Closes tasks.lthn.sh/view.php?id=731 (§5 only — §4/§8 are separate lanes) Co-authored-by: Codex <noreply@openai.com>
Stamp + zero-value-usable GrammarImprint type. Imprint(node, ctx) derives deterministic HLCRF-style paths via block coordinates, hashes (Path + node type + child count) via stdlib FNV (// AX-6-exception: structural hash, not crypto). Tags structural states: leaf, branch, empty, truncated. Never reads text/raw content; never calls Render. AX-10 Good/Bad/Ugly tests pass via GOWORK=off + temp GOPATH. Closes tasks.lthn.sh/view.php?id=731 (§4 only — §6/§5/§8 are separate lanes) Co-authored-by: Codex <noreply@openai.com>
wasm.go (js && wasm build tag): RenderToString(node Node) string, registered as globalThis.coreHTML.renderToString(nodeJSON) via syscall/js.FuncOf. JSON node bridge inlined here. syscall/js annotated with // AX-6-exception (no core/* primitive for JS bridging). Normal `go build ./...` passes (file excluded by build tag). Cross-compile verified: GOOS=js GOARCH=wasm go build . — clean. WASM tests documented, not run in sandbox: GOOS=js GOARCH=wasm go test -run 'TestRenderToString' . Closes tasks.lthn.sh/view.php?id=731 (§8 only — completes the four-section sub-lane series for #731; consumer migration of the variadic Entitled() shape is a separate follow-up if/when needed) Co-authored-by: Codex <noreply@openai.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (55)
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Pull request overview
Routine dev→main sync PR that consolidates recent go-html changes, including module/dep migration, new WASM and API surfaces, and a revised deterministic data-block path scheme.
Changes:
- Migrates the module/import paths to the
dappco.re/go/*family and updates consumers/tests/docs accordingly. - Revises layout/responsive rendering to use dotted
data-blockcoordinates (and updates parsing/tests) plus adds responsive media hints. - Adds new surfaces: WASM
globalThisbridge (coreHTML.renderToString), a Gin-based API provider, and expanded web-component codegen (incl. TS defs).
Reviewed changes
Copilot reviewed 56 out of 58 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| wasm_test.go | Adds WASM-side tests for the globalThis.coreHTML.renderToString bridge. |
| wasm.go | Introduces a WASM JS bridge that parses JS values into Nodes and renders to string. |
| text_translate_default.go | Switches default translation import to the new i18n module path. |
| text_translate_args.go | Adds count-argument normalization/injection for i18n.count.* keys. |
| text_translate.go | Injects normalized translation args before delegating to translator/default. |
| tests/cli/html/Taskfile.yaml | Adds CLI task runner for build/vet/test in tests. |
| shadow_test.go | Adds tests for Web Component JS output and naming helpers. |
| shadow.go | Introduces ShadowComponent JS generation + JS string literal escaping helpers. |
| responsive_test.go | Updates tests for dotted block IDs and adds media-hint test coverage. |
| responsive.go | Adds Responsive.Add(..., media) and preserves layout-path rendering through responsive. |
| render_test.go | Updates i18n import path in render tests. |
| render.go | Adds WASM-size budget note; keeps Render helper dependency-free. |
| pkg/api/provider_test.go | Adds tests for the new provider metadata and base path. |
| pkg/api/provider.go | Adds a Gin provider wrapper exposing /render and /grammar/check + route metadata. |
| pkg/api/handlers_test.go | Adds handler tests for render and grammar endpoints. |
| pkg/api/handlers.go | Implements /render and /grammar/check handlers. |
| pipeline_test.go | Adds StripTags regression tests and deterministic CompareVariants key ordering test. |
| pipeline.go | Improves StripTags correctness and makes CompareVariants deterministic + context cloning. |
| path_test.go | Updates/expands tests for dotted block IDs and compatibility parsing. |
| path.go | Implements dotted + legacy-hyphenated ParseBlockID parsing with validation. |
| node_test.go | Adds coverage for new block-path propagation and Attr recursion through wrappers. |
| node.go | Adds layout-path rendering plumbing, typed-nil handling, and Attr recursion into Layout/Responsive. |
| layout_test.go | Updates slot semantics and data-block expectations to dotted coordinates. |
| layout.go | Changes slot semantics (L→nav), dotted data-block generation, and layout-path cloning renderer. |
| integration_test.go | Updates i18n import path in integration tests. |
| grammar_test.go | Adds determinism/path-budget tests for GrammarImprint. |
| grammar.go | Introduces structural GrammarImprint stamping without rendering content. |
| go.work.sum | Adds workspace sum entries for new dependency graph. |
| go.work | Adds Go workspace file. |
| go.sum | Updates sums to match dependency/module changes. |
| go.mod | Renames module to dappco.re/go/html, updates direct deps, and adds local replaces. |
| entitled_test.go | Adds tests for new Entitled checker overload behavior. |
| entitled.go | Adds EntitlementChecker interface and overload-style Entitled helper w/ empty sentinel. |
| edge_test.go | Updates deep nesting/path expectations and variant-validation expectations. |
| docs/index.md | Updates docs for new features/paths (but currently has module path mismatch vs go.mod). |
| docs/history.md | Updates project history notes (variant validation + TS defs). |
| docs/architecture.md | Updates architecture docs for new path format and Responsive media hints. |
| context_test.go | Adds tests for locale forwarding, metadata aliasing, and cloneContext behavior. |
| context.go | Adds Data/Metadata aliasing, locale selection logic, and cloneContext helpers. |
| codegen/typescript.go | Escapes tags when emitting TS HTMLElementTagNameMap entries. |
| codegen/codegen_test.go | Updates tests away from testify and expands tag/classname cases. |
| codegen/codegen.go | Adds reserved-name checks, JS string escaping, and adjusts tag→classname logic. |
| cmd/wasm/size_test.go | Updates imports and assertions; keeps WASM size gate test. |
| cmd/wasm/render_layout_test.go | Adds test ensuring empty slot strings still render containers. |
| cmd/wasm/render_layout.go | Adds shared legacy layout rendering helper. |
| cmd/wasm/register_test.go | Updates tests away from testify for the WASM component registration path. |
| cmd/wasm/register.go | Updates imports to new module paths for codegen/log. |
| cmd/wasm/main_test.go | Updates expected output for new data-block format and adds empty-slot test. |
| cmd/wasm/main.go | Changes WASM export behavior and adds template-string rendering with scalar substitution. |
| cmd/codegen/main_test.go | Updates tests away from testify and validates watch-mode behavior. |
| cmd/codegen/main.go | Refactors CLI to use core’s command system; adds generate/types/watch subcommands. |
| bench_test.go | Updates i18n import path in benchmarks. |
| Taskfile.yaml | Adds top-level task to build WASM output into dist/. |
| SESSION-BRIEF.md | Updates session brief to reflect current status/outputs. |
| README.md | Updates README content (but currently has module path mismatch vs go.mod). |
| .gitignore | Ignores dist/ output directory. |
| .core/release.yaml | Removes core release config. |
| .core/build.yaml | Removes core build config. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,61 @@ | |||
| // SPDX-Licence-Identifier: EUPL-1.2 | |||
There was a problem hiding this comment.
SPDX header tag is misspelled. Most license scanners expect the exact SPDX-License-Identifier token; SPDX-Licence-Identifier may not be recognized.
| @@ -0,0 +1,101 @@ | |||
| // SPDX-Licence-Identifier: EUPL-1.2 | |||
There was a problem hiding this comment.
SPDX header tag is misspelled. Most license scanners expect the exact SPDX-License-Identifier token; SPDX-Licence-Identifier may not be recognized.
| key := metadataAliasProbeKey(a, b) | ||
| marker := &struct{}{} | ||
|
|
||
| a[key] = marker | ||
| defer delete(a, key) | ||
|
|
||
| value, ok := b[key] | ||
| return ok && value == marker | ||
| } |
There was a problem hiding this comment.
sameMetadataMap() detects aliasing by temporarily writing a probe key into the caller-provided map. This has observable side effects and can introduce data races if the context maps are accessed concurrently. Consider tracking aliasing explicitly on Context (e.g., an unexported boolean set by NewContext/cloneContext) or using a non-mutating check (e.g., compare map header pointers via reflect/unsafe, if acceptable for WASM size).
| func structuralEachChildCount(node Node) int { | ||
| n, ok := node.(interface{ isNilHTMLNode() bool }) | ||
| if !ok || n.isNilHTMLNode() { | ||
| return 0 | ||
| } | ||
|
|
||
| value := reflect.ValueOf(node) | ||
| if !value.IsValid() || value.Kind() != reflect.Pointer || value.IsNil() { | ||
| return 0 | ||
| } | ||
| elem := value.Elem() | ||
| if !elem.IsValid() || elem.Kind() != reflect.Struct { | ||
| return 0 | ||
| } | ||
| items := elem.FieldByName("items") | ||
| if items.IsValid() && items.Kind() == reflect.Slice { | ||
| return items.Len() | ||
| } | ||
| return 0 |
There was a problem hiding this comment.
GrammarImprint treats any Each/EachSeq node as having 0 children unless it has a non-nil items slice. For EachSeq(), items is empty and seq is set, so structuralChildCount/structuralEmpty will report the node as empty even when it would render items. Consider either (1) materialising the seq for counting in imprinting, or (2) treating non-nil seq as “non-empty/branch” (possibly with a dedicated tag) so stamps don’t incorrectly collapse dynamic lists to leaf/empty.
| @@ -0,0 +1,333 @@ | |||
| //go:build js && wasm | |||
|
|
|||
| // SPDX-Licence-Identifier: EUPL-1.2 | |||
There was a problem hiding this comment.
SPDX header tag is misspelled. Most license scanners expect the exact SPDX-License-Identifier token; SPDX-Licence-Identifier may not be recognized.
| ```go | ||
| import "forge.lthn.ai/core/go-html" | ||
| import html "dappco.re/go/core/html" | ||
|
|
There was a problem hiding this comment.
Quick Start import uses dappco.re/go/core/html, but the module path in go.mod is dappco.re/go/html. This example won't compile as written; update the import path (and any other occurrences) to match go.mod.
| @@ -0,0 +1,78 @@ | |||
| //go:build js && wasm | |||
|
|
|||
| // SPDX-Licence-Identifier: EUPL-1.2 | |||
There was a problem hiding this comment.
SPDX header tag is misspelled. Most license scanners expect the exact SPDX-License-Identifier token; SPDX-Licence-Identifier may not be recognized.
| @@ -0,0 +1,102 @@ | |||
| // SPDX-Licence-Identifier: EUPL-1.2 | |||
There was a problem hiding this comment.
SPDX header tag is misspelled. Most license scanners expect the exact SPDX-License-Identifier token; SPDX-Licence-Identifier may not be recognized.
| @@ -0,0 +1,15 @@ | |||
| //go:build !js | |||
|
|
|||
| // SPDX-Licence-Identifier: EUPL-1.2 | |||
There was a problem hiding this comment.
SPDX header tag is misspelled. Most license scanners expect the exact SPDX-License-Identifier token; SPDX-Licence-Identifier may not be recognized.
| // SPDX-Licence-Identifier: EUPL-1.2 | |
| // SPDX-License-Identifier: EUPL-1.2 |
| func TestGenerateClass_ValidExtendedTag_Good(t *testing.T) { | ||
| tests := []struct { | ||
| tag string | ||
| wantClass string | ||
| }{ | ||
| {tag: "foo.bar-baz", wantClass: "FooBarBaz"}, | ||
| {tag: "math-α", wantClass: "MathΑ"}, | ||
| } |
There was a problem hiding this comment.
These tests assert that tags like "math-α" are valid custom element names. In browsers, custom element names are restricted to a specific ASCII-only pattern; non-ASCII names typically throw at customElements.define(). If this project targets standard Web Components, update the tests (and TagToClassName expectations) to only cover spec-valid tags.
Routine dev→main PR opened by Hephaestus PR-cadence task.
This PR exists to:
ahead_by: 55 commit(s) (per gh api compare)If CodeRabbit clears with no blocking comments, this PR is eligible for
gh pr merge --merge(real merge commit, no force-push). Conflicts and review feedback should be addressed on the dev branch before merge.Co-authored-by: Hephaestus hephaestus@cladius