Skip to content

release: v0.44.0-beta.2 promotion evidence (do not merge) - #1319

Closed
SisyphusZheng wants to merge 25 commits into
mainfrom
release/v0.44.0-beta.2-promotion
Closed

release: v0.44.0-beta.2 promotion evidence (do not merge)#1319
SisyphusZheng wants to merge 25 commits into
mainfrom
release/v0.44.0-beta.2-promotion

Conversation

@SisyphusZheng

Copy link
Copy Markdown
Member

Promotion evidence PR for the v0.44.0-beta.2 release (stage #1288, ADR-0151). Supersedes the closed #1315 per the release-lane discipline (dev tip repaired by #1318 at 005a971735b56043265bb39223147795e6c79fdc).

Per the release-lane discipline: this PR exists ONLY to produce the authoritative pr-full-ci-evidence artifact at the exact head SHA 005a9717. It will be CLOSED UNMERGED; main is advanced by exact-SHA ff-push, never by GitHub merge buttons.

SisyphusZheng and others added 25 commits September 3, 2026 20:35
#1289)

Supersedes dependabot PRs #1197/#1198, which bumped init and analyze
separately; CodeQL requires init/analyze version coherence, so the split
PRs fail in isolation.

Co-authored-by: DevBot <devbot@openelement.dev>
… truth (#1231) (#1290)

M14: add a deterministic local release lock (tools/autoflow/release-lock.ts)
taken by every release-mutating autoflow command (patch-release, release,
release-prepare, publish-existing, release-record). Acquisition is atomic
(createNew) under the gitignored .artifacts/ scratch dir; a second local
release operation fails closed and names the holder, and the lock is released
on both the Deno.exit and exception paths. CI mutual exclusion keeps using
the openelement-release concurrency group in autoflow-release.yml.

M16: one canonical prerelease/version truth implementation in
tools/lib/version.ts (import-free, so project-constants.ts stays loadable by
Nitro/jiti under Node). bump-version, check-strategic-docs,
check-version-anchors, check-docs-truth, check-release-truth,
npm-release-verifier, release-evidence-consistency, autoflow cli/release/
version-anchors and publish-npm now import parseLineVersion /
prereleaseParts / prereleaseSequence / prereleaseChannel / compareVersions /
nextPatchVersion / normalizeReleaseVersion from it instead of re-rolling
regexes; FIRST_TAGGED_VERSION ('0.41.0-alpha.14') now has a single copy
(previously hard-coded in both autoflow/release.ts and check-docs-truth.ts).

M17: the docs-truth current gate whitelist (CURRENT_DOC_ALLOWED) switches
from substring matching to exact-path semantics: trailing-'/' entries are
repo-anchored directory prefixes, all other entries are exact file paths.
Incidental substring exemptions (e.g. docs/runbooks/supabase-migrations.md
via 'migration') are now gated and pass the scan; dead entries dropped.

freeze:semantics local/CI diff-semantics gap (Beta.1 carried risk): the
module header now carries the precise characterization — divergence between
the origin/main local base and the origin/$GITHUB_BASE_REF CI base is
provably one-directional (fail closed) under the ADR-0151 train topology
(origin/main is an ancestor of every dev-based PR HEAD, so the local diff is
a superset of the CI diff while local amendment signals are a subset), and
documents why defaulting the local base to origin/dev would be fail-open for
dev→main release PRs.

Co-authored-by: DevBot <devbot@openelement.dev>
* fix(security): adjudicate open CodeQL alerts (#1281)

Fixes (8 alerts):
- element html-escape.ts (#4140/#4142/#4143/#4144): headExtras script strip
  now runs the block pass to a fixed point before the strip-to-EOF backstop
  (a single pass could emit a re-formed <script> or a live on* handler that
  the strip itself concatenated); the script end-tag pattern accepts
  attributes/whitespace per the HTML spec; the comment-balance check counts
  --!> as a close. Contract preserved: scripts/handlers are still stripped
  when allowHeadExtrasScripts is false; adversarial regression tests added.
- adapter-vite static-serve.ts (#4150): tryStatic reads candidates directly
  with failure-as-miss fallback instead of existsSync/statSync
  guard-then-read (TOCTOU). Mirrored in the generated serve.mjs template
  (ssg-helpers.ts); directory-candidate parity pinned by test.
- www site-ui article-body.ts (#4151): prepareArticle heading labels drop
  stray angle brackets the tag pattern cannot match, so a partial tag
  fragment can never reach the rail outline.
- tools check-public-docs-integrity.ts (#4131): stale-claim guard embeds the
  previous prerelease tag via the shared escapeRegExp (repo-standard full
  metacharacter escape); parity pinned by test.
- app spa-projection-guard.test.ts (#4170): drop the always-overwritten
  baseline initializer.

Dismissed via gh api with recorded rationale (see issue #1281):
- #4145 (used in tests): release.test.ts fixture intentionally embeds a
  template literal as text data mirroring project-constants.ts.
- #4148/#4149 (false positive): sitemap/robots writes target the developer's
  own dist output dir with pinned mode 0o644; overwrite-on-rebuild is the
  intended contract; tmpdir dataflow exists only in test fixtures.

No ADR-0122 frozen-semantics paths touched (freeze:semantics:check green).

* fix(www): strip article heading tags to a fixed point; drop hex-like issue ref from comment (#1281)

CodeQL js/incomplete-multi-character-sanitization re-fired on the
single-pass tag strip in prepareArticle (new alert on PR #1291); apply the
documented fixpoint idiom, matching the html-escape.ts sanitizeHeadExtras
structure. The www theme-token gate also read '(#1281)' on a line containing
'outline' as a hex color literal; reworded.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…) (#1292)

The deno test --coverage subprocess has died by SIGSEGV (exit 139) three
times under load with no test assertion failure, blocking a release-tier
gate by random crash. Classify the test-run exit: codes below 128 are real
failures and fail immediately without retry; signal exits (128 + signo)
are retried up to --crash-retries (default 2), each crash reported loudly
on stderr, and crash exhaustion fails the gate explicitly. Coverage
semantics unchanged: thresholds, scopes and full denominator untouched.

Co-authored-by: DevBot <devbot@openelement.dev>
 B2.12) (#1293)

Remove the long-lived NPM_TOKEN/.npmrc auth path from autoflow-release.yml
and gate npm publication capability on the GitHub Actions OIDC lane instead
of token env vars. The release job pins an explicit npm CLI floor
(npm@^11.5.1, verified at runtime) because Node 22's bundled npm predates
native OIDC support. Publish keeps --provenance in the Actions lane.

The no-token shape is mechanically enforced: pr-ci-workflow.test.ts fails
closed on any NPM_TOKEN/NODE_AUTH_TOKEN/_authToken reference in the release
workflow and requires id-token: write plus the npm floor step before publish.

npm-side trusted-publisher registration for the five @OpenElement packages
is a maintainer web precondition; see docs/runbooks/npm-trusted-publishing.md.

Beta.2 slice of #1187 (B2.12 on #1288).

Co-authored-by: DevBot <devbot@openelement.dev>
…B2.6) (#1294)

* feat(governance): offload generic checks to mature OSS tooling (#1156 B2.6)

ADR-0144 implementation slice:

- Replace the bespoke explicit-any checker (tools/check-type-safety.ts +
  test + task + AutoFlow gate) with deno lint's no-explicit-any rule
  (AST-based, stricter, green on all 887 linted files).
- Adopt markdownlint-cli2@0.23.2 for Markdown structure (thin
  .markdownlint-cli2.jsonc, gitignore-scoped, rule set green repo-wide;
  fixes 5 trailing-space + 3 EOF-newline violations in www/content/blog).
- Adopt gitleaks 8.30.1 (CI step, binary pinned by version + SHA-256) for
  secret scanning; delete the custom SECRET_CONTENT_PATTERNS regex scan
  from check-repo-hygiene.ts. .gitleaks.toml allowlists only deliberate
  Stripe placeholder fixtures.
- Adopt actionlint 1.7.12 (CI step, binary pinned by version + SHA-256)
  for workflow linting; clean on all 8 workflows.
- Adopt zizmor via zizmorcore/zizmor-action@v0.6.3 (pinned SHA registered
  in ACTION_VERSION_PINS, offline audits, advanced-security off) for
  workflow security; fix all 11 artipacked findings with
  persist-credentials: false, and suppress 4 findings with in-band
  reasons (release-lane credential persistence, pinned npm floor,
  GitHub-controlled template expansions).
- .github/zizmor.yml disables only the self-repository style audit
  (./local-action form is already audited by check-action-pins).

Net governance surface: -1 custom checker (-210 LOC incl. tests), -1
custom task, -1 custom AutoFlow gate, zero new workflows/jobs.

* fix(governance): satisfy actionlint shellcheck integration (#1156 B2.6)

actionlint on the ubuntu runner runs shellcheck over every run block
(absent locally on macOS); fix the six findings it reported: four
unused loop counters renamed to _, an intentional SC2086 word-split
and an intentional SC2016 single-quoted EICAR signature documented
with in-band disable comments.

* fix(governance): add Dependabot cooldown for action updates (#1156 B2.6)

zizmor-action audits dependabot.yml in addition to workflows (its
default input collection); fix the dependabot-cooldown finding with a
7-day bake-in period for github-actions updates.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…1229 B2.7) (#1295)

Co-authored-by: DevBot <devbot@openelement.dev>
…ivilege docs checker (#1230 B2.8) (#1296)

* refactor(governance): close M15 decision-test residual and L12 least-privilege docs checker (#1230 B2.8)

* feat(governance): gate release-line truth in ci/release tiers (#1230 B2.8 thinker follow-up)

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…rary decision (#1233 B2.11) (#1297)

- docs/governance/DEPENDENCY_POLICY.md: enforcement inventory (one mechanism
  per layer, no duplicate assertions found), deno.json specifier pin policy
  (lockfile+vendor is the pin; exact pins = deliberate-diff tooling and the
  URLPattern polyfill, caret ranges = shared platform libs and published
  package deps), and the explicit justified dual zod/valibot decision with
  its boundary rule.
- tools/check-validation-boundary.ts + test: mechanical gate asserting
  published package source imports no schema-validation library; registered
  as validation:boundary-check in the AutoFlow gate registry (ci/release).
- Pointers from PROJECT_WORKFLOW.md and docs/integrations/validation.md.

Closes #1233

Co-authored-by: DevBot <devbot@openelement.dev>
…te (#1226, B2.1) (#1298)

* fix(ui): repair platform semantics found by v0.44 dogfood qualification (#1226)

- open-dialog: the compiled bool sink can remove the inner dialog's `open`
  attribute before the component's sync runs; per the HTML spec, removing the
  attribute from a modal dialog leaves it :modal and close() is then a no-op,
  so the modal session never exits the top layer. The close branch now
  restores the attribute before close(). Also, the native close echo of a
  programmatic close no longer re-dispatches open-dialog-close.
- open-dialog: :state(open)/:state(closed) never applied in real browsers —
  the kernel attaches ElementInternals only for form-associated hosts, so the
  dialog attaches its own once via the instance-state module.
- open-dropdown: native popover focus return only works when the previously
  focused element shares the popover's tree; on real pages (host inside a
  page shadow root) focus dropped to <body> on dismiss. The trigger path now
  records the composed focused element at open time and restores it on close
  only when the platform failed to.
- open-input: formDisabledCallback mirrored onto the host `disabled`
  attribute, which the platform counts toward disabledness — a
  fieldset-disabled control could never be re-enabled. It now mirrors onto
  the (reflect: false) property.
- element: renderDsd threads the compiled delegatesFocus static into the DSD
  template as shadowrootdelegatesfocus; without it, claimed shadow roots
  silently lost focus delegation (SSR/CSR parity).

Covered by new unit pins in packages/ui/__tests__/components.test.ts and
packages/element/__tests__/compiled-server/compiled-composition.test.ts, plus
the ui-dogfood browser evidence in the follow-up commit.

* test(adapter-vite): add @openelement/ui dogfood qualification fixture + CI gate (#1226)

Adds packages/adapter-vite/__fixtures__/ui-dogfood: an app consuming
@openelement/ui as an external consumer (packageIslands via the WC Package
Protocol manifest, plain page markup, no fixture-private shims). Every route
is static prerendered, so each page exercises the real compile -> SSR/DSD ->
serve -> hydrate path.

Playwright evidence (Chromium + Firefox + WebKit):
- open-dialog: SSR-open attribute -> top-layer modal choreography, trigger
  open, focus containment, Escape close, focus return, single-event close,
  :state(open)/:state(closed).
- open-tabs: WAI-ARIA roles/states/relations on live light-DOM children,
  roving tabindex, click selection, ArrowLeft/Right wrap + Home/End with
  focus following selection, reconnect/dispose effect teardown and re-sync.
- open-dropdown: anchor-pair assignment, trigger toggle with the
  pointerdown guard, Escape/outside-click light dismiss, focus return.
- open-input/open-button: FormData participation (incl. activation-time
  initial value), valueMissing blocking, formResetCallback,
  formDisabledCallback + fieldset re-enable, delegatesFocus, per-input
  events.
- boundaries: shadow-open/light/shadow-closed contracts side by side,
  incl. a no-JS render pass.
- claim: customElements.define-wrapped node-identity proof that hydration
  claims the parsed DSD/light DOM instead of re-rendering.

CI wiring: fixture:ui-dogfood:{build,e2e,e2e:browsers,gate} deno tasks plus
an autoflow policy gate (ci + release tiers) triggered by packages/ui,
packages/element, adapter-vite src/fixtures, and deno.json — the same
three-browser CI job pattern as fixture:request-time:gate.

* style(ui-dogfood): apply repo-root deno fmt/lint to fixture e2e (#1226)

The fixture-local deno.json excludes e2e/ from fixture-rooted invocations
(same pattern as the request-time fixture), but repo-root deno fmt/lint walk
the whole tree under root config. The specs were only ever checked
fixture-locally, so they drifted; run 33808083057 caught it.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…ics (#1227, B2.2) (#1299)

Close independent-audit findings L4/L5 for @openelement/ui:

- L4 theme-toggle: per-instance priority-chain resolution, document-channel
  convergence between instances, dual-state transitions on all three channels
  (host attribute, document data-theme, colorScheme), no-op re-apply, reconnect
  exactly-once (initDone guard), teardown-free dispose with fresh replacement
  init, attribute-change-never-persists (#804 complement).
- Dispose/reconnect pins for dialog (open-effect teardown + top-layer
  re-entry per session), tabs (click wiring once per tab across reconnect,
  stale-ARIA re-sync), dropdown (focus-return wiring once, stable anchor
  name), input (activation id stability, open-focus/open-blur events).
- L5: manifest attribute/event contract test (WC Package Protocol surface);
  shared fake-DOM harness extracted to __tests__/harness.ts.
- Documented not-unit-observable semantics (computed reactivity,
  ElementInternals channels, connectedCallback scheduling) with pointers to
  the ui-dogfood + www browser evidence instead of fake-passing unit tests.

Co-authored-by: DevBot <devbot@openelement.dev>
…ace (#1177) (#1300)

* test(tools): gate www public-import boundary against published export maps (#1177, B2.3)

The website is an npm-first consumer of the five retained packages. Prove
mechanically that every @openelement/* specifier in the shipped site surface
(www/app plus vite.config/content-collections/build-pagefind) resolves to a
published export subpath — never a private source path — so in-repo workspace
resolution is identical to the packed npm artifact boundary. Negative control:
a temporary private-source import fails the gate.

* docs(www): retire present-tense 0.43 product claims from current-truth pages (#1177, B2.3)

The architecture collection described the WC SSR classification, corpus and
the Supabase x Cloudflare composition path as 'the 0.43 line' in present
tense while the current line is the compiled v0.44 line; the machinery is
CI-gated on dev (third-party-wc:smoke, fullstack qualification), so the
claims now name the current line and record the 0.43 origin as history.
comparison.md scopes its adoption caution to the stable 0.43 line explicitly.
The 0.41 migration guide gains a historical-record banner: the current line
is consumed fresh via @openelement/create, with no supported 0.43 -> 0.44
in-place upgrade (B2.5 ruling).

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…trinsic transform (#1301) (#1302)

The packed npm artifact of @openelement/ui could not be SSR-admitted via
the documented packageIslands path: deno pack transpiles the component
.tsx sources to .js with TC39 decorator lowering (applyDecs2203R), which
erases the compile-time-only @element/@Property intrinsics (ADR-0143 —
their runtime exports are inert no-ops by design). No Part Program
registered from the packed modules, so SSG failed closed with
OE_PROGRAM_MISSING. In-repo consumers never saw this because the adapter
auto-aliases workspace members to source (workspace-alias.ts).

The admission contract is unchanged. The pack pipeline now runs the same
open:compiled-element intrinsic transform a consumer build would run:
packages shipping compiled-element sources are packed from a staged
temporary workspace whose component modules carry the compiler output, so
deno pack transpiles compiled form (semantics-preserving) instead of
lowering the intrinsics away.

Adds consumer:packaged-ui, a CI-gated (ci + release tiers) packed-artifact
consumer qualification: the five pack:dry-run tarballs are installed into
a hermetic scratch consumer outside the repository, a minimal app admits
@openelement/ui via packageIslands, and the prerendered HTML must carry
the compiled DSD for <open-theme-toggle>. RED pre-fix (build fails,
OE_PROGRAM_MISSING), GREEN post-fix.

Co-authored-by: DevBot <devbot@openelement.dev>
…il-closed CI gate (#1157, B2.4) (#1303)

Define the normalized entry/source-location/locale/reference/fingerprint
schemas (tools/lib/content-graph.ts) and the five Beta.2 adapters
(tools/lib/content-graph-adapters.ts): Markdown collections via the
adapter-vite collection loader, public API data from the PACKAGE_SURFACE.md
machine blocks, compiler metadata from the @openelement/ui generated
manifest, the roadmap timeline via the repo's TypeScript AST tooling, and
release truth from docs/release.

The generator (tools/generate-content-graph.ts) writes
www/app/data/_generated-content-graph.json deterministically (sorted
entries/alternates/references/keys; sha256 fingerprints) and --check is the
CI drift gate registered in the AutoFlow policy. Validation fails closed on
duplicate ids, broken entry/route references and false locale alternates
(orphan locales, asymmetric pairs, byte-identical 'translations').

Deterministic queries for doc routes, locale availability, search records
and per-route SEO metadata are exposed for the #1159 consumers.

Co-authored-by: DevBot <devbot@openelement.dev>
…tory truth (#1158, B2.4) (#1304)

Generate www/app/data/_generated-api-reference.ts from the real public
exports of every supported subpath (TypeScript compiler API enumeration
with workspace paths resolution, matching the public-interface snapshot),
each export's JSDoc summary and declaration location, the PACKAGE_SURFACE.md
stability classes, and the @openelement/ui compiler manifest (tags,
attributes, events, slots, CSS parts, SSR/DSD layer, hydration/activation).

The generator fails closed on unclassified exports, stale classifications
(removed exports), undocumented stable-candidate exports, internal exports
leaking into the documented surface, and duplicate anchors. --check is the
CI drift gate (byte-identical regeneration), registered in the AutoFlow
policy.

The handwritten API inventory in www/app/routes/apilist.tsx is gone: the
route consumes the generated inventory and keeps only authored bilingual
prose, with a fail-closed projection that refuses stale or missing copy
keys. check-package-surface.ts now validates the generated module's
subpath inventory against each package's exports map instead of regexing
handwritten literals.

Comment-only JSDoc summaries were added to previously undocumented
stable-candidate exports across packages (ADR-0151; no behavioral change —
freeze:semantics:check and the public interface snapshot are unchanged).

Co-authored-by: DevBot <devbot@openelement.dev>
…es with fail-closed gates (#1159, B2.4) (#1305)

* feat(tools,www): drive www nav/locale/link/SEO truth from owned sources with fail-closed gates (#1159, B2.4)

- tools/check-www-links.ts + tools/lib/www-links.ts: built-output internal
  link/fragment gate over www/dist (every internal href/src resolves to a
  built file; every #fragment anchors; every sitemap.xml URL resolves) plus
  per-page SEO invariants (exactly one <title>, non-trivial meta
  description, og:title). Wired into the build task so the CI build gate
  fails on broken links. First run found and this change fixes real broken
  links: CHANGELOG.md's repository-relative links are now projected onto
  the canonical GitHub tree at the changelog route's render seam.
- tools/check-www-truth.ts: the remaining hand-maintained surfaces must
  mechanically agree with owned truth — _generated-nav.ts byte-identical
  regeneration of route meta + vite.config headerNav (read through the TS
  AST), headerNav hrefs resolve to scanned routes, bilingual locale
  availability (orphan/missing zh and byte-identical en/zh pairs fail), and
  the CURRENT roadmap entry names the package version tag.
- tools/check-content-examples.ts: ts/tsx guide examples importing
  @openelement/* type-check against the real framework sources (en/zh
  duplicates deduped); only documented snippet elision (consumer-project
  imports, elided app names, implicit any, the uninferred loader-data
  generic) is suppressed — framework-surface errors fail closed.
- AutoFlow policy: www:check-truth and content:examples-check registered
  (ci + release tiers); the build gate's triggers cover the link checker.

Version constants and release-state agreement were already pinned by
docs:check-version-anchors / release:truth:check; this composes with them
instead of duplicating. Scheduled external link checks stay deferred to
Beta.3 under #1156 (workflow cap 8 — no ninth workflow added).

* fix(tools): create .tmp before content-example compilation (#1159)

Clean CI checkouts do not carry the gitignored .tmp directory, so
Deno.makeTempDir({ dir: '.tmp' }) failed closed (NotFound) in
content:examples-check and its tests. Create it recursively first.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…, B2.10) (#1306)

* test(www,e2e): harden E2E selectors and cover the full public IA (#1232, B2.10)

M19: replace ad-hoc shadow-piercing and styling-class selectors with
user-visible semantics (roles, accessible names, landmarks, stable routes)
across the www e2e suite; the search island gains real dialog/region/input
ARIA semantics instead of test-only hooks. Structural probes that test the
DSD/shadow contract itself keep structural queries by design.

M20: www/e2e/public-routes.spec.ts derives the full public route list
mechanically from the built sitemap at collection time and smoke-covers
every public route (status, locale lang, main landmark, visible h1, no
uncaught page error) on all three CI engines via the browser-smoke legs; a
fail-closed cross-check requires every content-graph article route (both
locales) to appear in the sitemap. Playwright reporters are CI-visible
(github annotations + html report + failure artifact upload), and the
fullyParallel/workers contradiction in www/e2e is resolved (2 on CI, 50%
locally); the serial fixture/starter configs document their coherence.

* chore(adapter-vite): refresh request-time fixture lockfile to 0.44.0-beta.1 workspace links

The committed lock still referenced 0.43.3 workspace links; the fixture
build rewrites it to the current package line. Committed separately from
the #1232 change set to keep the drift visible.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
… (#1308)

Major:
- /apilist renders the generated API + custom-element reference: 167
  per-export entries and 10 per-element detail rows with the generated
  anchors; the built-output link gate now asserts every generated
  searchRecord anchor exists in both locales (pagefind skip documented).
- /zh/contributing ships a real zh translation instead of hard-coded
  English; the www:check-truth locale gate now covers route-level
  content records (en without zh fails closed) and requires every blog
  post to declare its original language via frontmatter lang. Blog
  routes mark locale-mismatched renders with an explicit notice and a
  truthful lang attribute instead of masquerading.

Minor:
- Per-route, locale-appropriate title/description/og/canonical/hreflang
  derived from the content graph (content routes) + an authored
  bilingual route map (www/app/seo.ts), applied to the built shell by
  tools/apply-www-seo.ts (fail-closed) before Pagefind indexing;
  findSeoFailures strengthened beyond presence-only (boilerplate-title
  rejection, canonical/hreflang presence, per-locale title uniqueness,
  no English boilerplate description on zh pages).
- Sitemap generator excludes locale-prefixed 404 pages symmetrically
  (/zh/404 leak fixed).
- Changelog copy now names the withdrawn npm beta.1-beta.3 artifacts as
  the 0.41.0-era line; CHANGELOG.md gains reconciling 0.43.x and
  0.44.0-beta.1 entries deferring to docs/release/.
- content-examples gate: typescript/js fence aliases are type-checked,
  TS2304 suppression no longer covers documented framework exports
  (caught a real import-elided openElement() call in the configuration
  guide), blog exclusion documented with rationale.

Also fixes the content-graph blog adapter to derive slugs/routes through
the blog plugin's own collection options (date-prefix transform), so
graph routes match the served routes.

Co-authored-by: DevBot <devbot@openelement.dev>
…nsumer paths (#1228, B2.5) (#1309)

* fix(create): actionable CLI errors and npm-rule project-name validation (#1228)

L9: every create failure mode (invalid name, existing directory,
permission/write errors, unexpected defects) now exits 1 with one
actionable message via a top-level catch — never a stack trace.

L11: validateProjectName enforces npm package-name rules (lowercase,
start with letter/number, [a-z0-9._-], 214-char ceiling) and rejects
'..' traversal segments before any filesystem work, with unit and
subprocess tests.

* test(tools): exercise the full consumer lifecycle from packed artifacts (#1228)

Extend consumer-packaged-starter.ts (CI gate consumer:packaged) from
check+build to the complete adopter lifecycle against the five packed
tarballs in a hermetic scratch outside the workspace: dev (vite dev
server SSR probe), check, test, build, start (cli/start HTTP probes for
static, request-time and API routes), deploy (standalone
dist/server/serve.mjs probes), and preview (fail-closed refusal with
start guidance for a dynamic app, #601).

* ci: boot dist/server/serve.mjs under pinned Bun as a required leg (#1228)

The deployment guide and PACKAGE_SURFACE.md claim generated artifacts
run on Bun; the only evidence was local. Add bun-serve-smoke to
autoflow-ci: the request-time fixture is built and its standalone
serve.mjs is booted under Bun 1.4.1 (release download pinned by
SHA-256, verified against oven-sh/bun SHASUMS256.txt) with the same
HTTP probes as the Node 24 leg. The job joins the pr-full-ci-evidence
needs list; the workflow contract test is updated to match.

* docs(examples): record OEC9008 exclusion carry and pin fresh example to the published line (#1228)

Desktop examples: the bounded-repair probe showed the route-module
restructure cascades into full render() re-authoring (OEC9007/OEC9006
behind OEC9008), so the examples are excluded from qualifying consumer
evidence with a documented carry to Beta.3 (B3.8); check/smoke stay
green and CI-gated.

open-element-in-fresh: move @openelement/ui from the stale ^0.42.0 to
the published 0.44.0-beta.1 the README already claims; deno task check
passes against the packed/published surface.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…idue audit gate (#1310)

* docs(adapter-vite): correct catch-all pattern in route-manifest module doc (#1273 O1)

The module doc documented routes/products/[...slug].tsx as /products/*,
but scanRoutes (#556) converts a catch-all segment to the Hono named-regex
parameter :slug{.+} matching across '/'. Pinned by
__tests__/route-manifest.test.ts ('catch-all [...slug].tsx →
/products/:slug{.+}'). Comment only; no behavior change.

Refs #1273

* refactor(element): remove dead v0.43 renderer/hydration residue (#1273 O2, B2.13)

Dead-code proof (import graph from every deno.json exports entrypoint +
CLI/bin entries, plus repo-wide symbol search incl. tests, www, tools,
examples): zero consumers for each removal. All five deleted modules were
shipped to npm because every package publishes src/**.

Deleted:
- src/types.ts (ElementDefinition render()->VNode typing of the removed
  runtime renderer)
- src/internal/protocol/vnode.ts (VNode/ComponentFn/ComponentCtor/RenderFn)
- src/internal/protocol/prop.ts (ADR-0052 static prop-decl typing,
  superseded by compiler __compiledProperties)
- src/internal/core/dom-utils.ts (clearChildren, unused since #902-era
  renderer removal)
- src/internal/core/dsd-shadow-root.ts (hasPopulatedShadowRoot, unused)

Slimmed:
- internal/protocol/render.ts: dropped the legacy DSD-pipeline interfaces
  (RenderPhase, RenderInput, RenderHooks, DsdOptions, RenderErrorCode,
  DsdComponentConstructor, DsdComponent) and the VNode import; kept the
  live RenderError/RenderOutput/HydrationHint/DsdRenderMetrics/
  SsrAdmissionDecision contract unchanged (snapshot shapes identical).
- internal/protocol/hydration-markers.ts: removed the v0.43 marker
  constants (DATA_SIGNAL*, DATA_EID, DATA_SSR_PROPS, BRANCH_MARKER_PREFIX,
  FOR_ITEM_PREFIX, FOR_END_PREFIX) and parseSignalAttrSpec. The compiled
  model claims through oe:pN program anchors; the marker literals are
  already forbidden in built artifacts by check-v044-legacy-absence.ts.
  DATA_OE_LIGHT stays: it is the live ADR-0142 light-mode marker, consumed
  via literals across the generated-code boundary by design.

Public surface: DATA_SSR_PROPS re-export removed from src/index.ts and
src/public-runtime.ts. The data-ssr-props channel was already documented
as gone (app/preact.ts); the export was classed internal-importable, had
no consumer anywhere in the repo, and is deleted rather than deprecated
per the B2.13 removal authority. Interface snapshot, package-surface
class map and content graph regenerated; the only snapshot delta is the
DATA_SSR_PROPS symbol removal.

Also fixes the stale reader list in ssr-registry-markers.ts (element's
define-element.ts no longer exists; the SSR stub marker is read by
app/preact.ts).

Refs #1273. Stage #1288 risk #8.

* test(tools): gate published artifacts against dead v0.43 residue (#1273, B2.13)

check-package-artifacts.ts scans the packed npm tarballs (which ship
src/**), so it is the cheapest honest place to keep the B2.13 deletions
from silently reappearing in a release:

- FORBIDDEN_LEGACY_PATHS: the five proven-dead @openelement/element
  modules removed in the B2.13 audit fail the gate if they ever re-enter
  the packed artifact.
- FORBIDDEN_LEGACY_SOURCE_PATTERNS: the removed marker-hydration channel
  (DATA_SSR_PROPS export, data-eid/data-signal* attributes,
  oe-branch:/oe-for-item: comment markers) is rejected in comment-stripped
  packed sources, extending the check-v044-legacy-absence.ts dist contract
  to the published src payload.

The gate is already wired at ci+release tiers in tools/autoflow/policy.ts
(package-artifacts:check) and runs before consumer:packaged. Unit tests
cover both rules plus comment/other-package false-positive guards.

Refs #1273. Stage #1288 risk #8.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…uild-truth claim (#1312) (#1313)

* fix(www): replace stale benchmark route/sitemap counts with durable build-truth claim (#1312)

The benchmark page (en+zh) asserted '30 route modules, 205 sitemap URLs',
handwritten and stale since PR #1106 — the candidate build emits 146 sitemap
URLs across 150 pages from 34 route files, and the false claim shipped
verbatim in built HTML (verifier NO-GO F1).

Adjudication per derive-from-owned-truth: the counts add no benchmark value
(the page measures properties, not site scale) and cannot be derived into
Markdown without new injection machinery, so the volatile numbers are removed
in favor of a durable architectural property — every route prerendered, the
sitemap built from routes. No numeric claim remains to silently rot; en/zh
parity and locale availability stay under the existing www:check-truth and
content-graph gates, and the content-graph fingerprints are regenerated.

* style(www): deno fmt table padding on benchmark pages (#1312)

Root deno fmt re-pads markdown tables to cell width; my edited cells
changed the column widths. Content-graph fingerprints regenerated to
match the formatted sources.

---------

Co-authored-by: DevBot <devbot@openelement.dev>
* docs(v0.44): preserve Beta.2 closure verification evidence (#1288)

Fresh-verifier closure report (NO_GO on F1 at aa3dd70), the remediation
re-verification addendum (GO at 89d3736), and the verifier-added
gate-teeth tests for the packed-artifact legacy-residue gate.

* docs(v0.44): role-neutral phrasing in Beta.2 closure evidence (#1288)

---------

Co-authored-by: DevBot <devbot@openelement.dev>
… repair (#1288) (#1316)

* fix(release): prepare regenerates derived truth and release-state anchors (#1288)

The v0.44.0-beta.2 bump commit passed the fast prepare gates but failed dev
CI (run 33885147030) and promotion PR #1315 (run 33885139920) on every
derived-truth gate the prepare plan did not re-run: content-graph:check
(bump rewrites graph sources), release:truth:check (release-state planning
anchors), docs:check-version-anchors (VERSION_PLAN STATUS-form head pair)
and www:check-truth (zh roadmap CURRENT entry).

The prepare/release plan now advances the release-state planning anchors
(activeTarget/nextPlannedTrain; published fields stay finalize-owned),
regenerates the content graph, and stages both artifacts in the bump
commit. buildVersionAnchorReplacements covers the VERSION_PLAN
repository/registry head pair and the next-public-prerelease anchors, and
bumpProjectConstantsText advances NEXT_PUBLIC_PRERELEASE with the
prerelease successor (the #813 binding #1283 fixed by hand). The roadmap
version anchor now rewrites both CURRENT-stamped entries (en + zh).

* fix(release): v0.44.0-beta.2 post-prepare consistency repair (#1288)

Follow-up to the 10744cc bump commit, which failed dev CI (run
33885147030) and promotion PR #1315 (run 33885139920) on the
derived-truth gates the prepare plan did not re-run. Applies exactly the
steps the fixed prepare plan now performs, plus the human release prose
the gates deliberately reserve for a human:

- regenerate www/app/data/_generated-content-graph.json (bump rewrote
  graph sources version.ts/roadmap.tsx)
- release-state.json planning anchors: activeTarget v0.44.0-beta.2,
  nextPlannedTrain v0.44.0-beta.3 (published fields stay on the beta.1
  prepare-window lag; finalize owns them)
- VERSION_PLAN.md STATUS-form head pair (Repository package line / npm
  registry line) advanced to v0.44.0-beta.2 with the prerelease dist-tag
  annotation release:truth:check requires
- NEXT_PUBLIC_PRERELEASE and the next-public-prerelease doc anchors
  advance to v0.44.0-beta.3 (the #813 in-flight binding #1283 fixed by
  hand for Beta.1)
- www roadmap CURRENT entries (en + zh): zh version advanced, and the
  Beta.2 theme/copy written (productization + governance offload,
  ADR-0151) — the superseded-theme gate is human by design
- README/README.zh/VERSION_PLAN/STATUS/ROADMAP head-zone prose updated to
  the Beta.2 line

Gates now green locally: content-graph:check, release:truth:check,
docs:check-version-anchors, www:check-truth, www:check-current-truth,
docs:truth, release:state-machine:check, release:evidence:check,
api-reference:check, content:examples-check, text-integrity:check, build
(incl. www:check-artifact-truth + www:check-links).

---------

Co-authored-by: DevBot <devbot@openelement.dev>
…hell refactor (#1318)

* fix(www): restore docs sidebar + footer chrome lost in the compiled-shell refactor (#1317)

Root cause: 7bbef34 (ADR-0143 compiled-shell refactor) deleted the
.docs-sidebar styles and the rich four-column footer from open-layout;
the follow-up test cleanup codified the stripped chrome instead of
restoring it, while entry-render-runtime kept injecting navItems /
currentPath / locale / home into the shell props every render.

Restores:
- docs sidebar (desktop sticky nav + mobile native-details disclosure,
  #995 idiom) driven by the previously-dead _generated-nav navSections,
  filtered to the active section family with aria-current page marking
- four labeled footer navigation columns (product/resources/company/
  legal, en/zh) + footer-bottom strip; orphaned `padding: 0` media rule
  replaced with real responsive grid collapse
- header nav links now carry localized hrefs and aria-current state

Coverage hardening (the process gap that let this ship green):
- site-chrome.spec.ts: semantic sidebar/footer assertions (section
  filtering, active marking, home renders no sidebar, mobile
  disclosure, four labeled columns, bilingual targets)
- visual-baselines.spec.ts: dedicated footer/sidebar element snapshots
  (every locale x theme x viewport on home, guide, architecture) —
  the route sweep's fullPage:false never captured the page bottom
- accessibility-performance.spec.ts: footer keeps the zero-headings
  invariant but now also asserts 4 navigation landmarks + structured
  link targets, so the bare-strip regression cannot pass again
- open-layout-navigation.test.ts: pure-function policy tests for URL
  safety, locale canonicalization, section filtering, footer model

* fix(element): attribute promotion must not be clobbered by pre-upgrade null sets (#1318)

Hydration on every non-default-locale page failed with
`[compiled-claim] item attribute drift on "href"`: the claim-time
re-derivation of computed shell chrome (sidebar rows, footer columns)
saw default-value signals while the SSR DOM was rendered from
locale-injected props.

Root cause chain (facade-host):
1. A pending pre-upgrade property write of `locale: null` (no real
   assignment intent) was coerced by applyPendingOwnValues into the
   compiled default ('en') and applied AFTER syncAttributesToSignals —
   clobbering the attribute-promoted 'zh'.
2. Generated field initializers that merely restate the compiled default
   were likewise captured as pending pre-upgrade sets.

Fixes:
- restatesDefault(): generated initializers that restate the compiled
  default (their documented contract, see reconcileOwnProperties) no
  longer enter pendingOwnValues.
- applyPendingOwnValues(): null/undefined pending values carry no
  pre-upgrade intent and are skipped instead of being coerced to the
  default over the promoted attribute value.

Element suite: 254 passed. WWW e2e chromium: 219 passed including
public-routes zh sweep and visual baselines.

* fix(www): de-duplicate footer chrome baselines (route-invariant chrome)

The footer is identical across routes for a given locale/theme/viewport,
so per-route footer snapshots are byte-identical and fail the
exact-duplicate baseline gate (#1230 M15). The footer now owns ONE
baseline per locale x theme x viewport (shot on the home route); the
docs sidebar keeps its per-route baselines because its section filtering
makes each route's chrome distinct. Desktop sidebar baselines were
regenerated under the fixed property-contract behavior (claim now
succeeds and the island actually hydrates, so the committed pixels
reflect the hydrated shell rather than the pre-fix stuck-SSR state).

* fix(www): drop the locale dimension from sidebar chrome baselines

Sidebar labels come from the untranslated generated nav, so en and zh
sidebar pixels are identical and the en/zh pairs fail the
exact-duplicate baseline gate. Sidebar baselines are now shot on the en
locale only, keyed by theme x viewport x route (zh sidebar semantics
stay covered by site-chrome.spec.ts).

---------

Co-authored-by: DevBot <devbot@openelement.dev>
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

APIError: Insufficient Balance

opencode session  |  github run

@SisyphusZheng

Copy link
Copy Markdown
Member Author

Promotion evidence recorded: AutoFlow CI run 33952061343 (exact SHA 005a971) green including pr-full-ci-evidence artifact. Closing unmerged per release-lane discipline; main advances by exact-SHA ff-push.

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.

1 participant