Skip to content

Measure successful Initializr downloads - #5591

Merged
shai-almog merged 3 commits into
masterfrom
fix/initializr-download-metric
Aug 23, 2026
Merged

Measure successful Initializr downloads#5591
shai-almog merged 3 commits into
masterfrom
fix/initializr-download-metric

Conversation

@shai-almog

@shai-almog shai-almog commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • record a consent-gated Crisp event only after the Initializr JavaScript download path succeeds
  • relay the completed download from the embedded app to the host page without user or project data
  • assert in website CI that the translated app, native bridge, and host listener all contain the production event path

Verification

  • production-equivalent website build with Initializr enabled and other embedded apps disabled
  • generated translated_app.js contains the acknowledged downloadProject bridge
  • generated native bridge and /initializr/ page contain cn1-initializr-project-downloaded
  • generated bridge regression proves a failed anchor click returns false and emits no event
  • node docs/website/scripts/test-cn1-crisp-events.mjs
  • node --check scripts/initializr/javascript/src/main/javascript/com_codename1_initializr_WebsiteThemeNative.js
  • Initializr common Maven tests on Java 8
  • repository copyright-header check

The generated Initializr bundle is intentionally not committed; the website workflow rebuilds it from repository sources for previews and production deployment.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4c40e1fc9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog
shai-almog merged commit 9f5b933 into master Aug 23, 2026
11 checks passed
@shai-almog
shai-almog deleted the fix/initializr-download-metric branch August 23, 2026 15:47
shai-almog added a commit that referenced this pull request Sep 7, 2026
…5724)

* Register the MCP server with Codex, and unblock the initializr suite

Codex was detected and then skipped: MCPClientRegistrar only knew how to edit a
JSON "mcpServers" object, so ~/.codex/config.toml was marked non-writable and
"Install in MCP Hosts" could neither add the entry nor remove it (discussion
#5700). One file covers all three Codex clients - the ChatGPT desktop app, the
CLI and the IDE extension share it.

MCPToml edits that file as TEXT rather than parsing and writing it back. It
walks the document far enough to know where every table and key assignment
begins and ends - tracking strings, multi-line strings, arrays, inline tables
and comments, so a "[" at the head of a line inside an array is never mistaken
for a table header - and then rewrites only the byte range belonging to one
server. Everything else survives exactly as the user left it: other servers,
settings, comments, key order, formatting, line endings, a BOM. A parse and
reserialize round trip could not promise that.

The other half of the promise is refusing. A document that is not valid TOML,
or one that declares this server in a shape the editor does not rewrite - a
dotted key, an inline table, an array of tables, or twice - is reported and
left untouched. Losing a Codex configuration is worse than not registering.
Server names and env keys are quoted when they are not bare keys: written bare,
a dot in a name would silently become two nested tables instead of one server.

Verified against the real thing, not only against ourselves. 800 generated
documents were cross-checked with Python's tomllib (output parses, the entry is
exact, every other key unchanged, removal restores the original), and the whole
cycle was round-tripped with the codex CLI: it reads what we write, and we
update and remove an entry it wrote without disturbing its neighbours.

The registrar's host table now carries a config format instead of a writable
flag, and the desktop menu names any host it could have written and did not, so
a refusal reaches the user rather than only the log.

Generated projects ship the pointer an agent needs: a new skill reference on
driving the RUNNING simulator over MCP - serve, register, then ui_snapshot /
ui_find / ui_set_text / ui_activate - indexed from SKILL.md and AGENTS.md. That
loop answers whether a flow BEHAVES right, which a screenshot cannot.

Making that verifiable meant repairing the initializr's javase module, which
has not compiled since #5591 added downloadProject to WebsiteThemeNative and
left the simulator implementation behind. With it building again the test suite
runs, which surfaced three stale assumptions in GeneratorModelIntegrationBuildTest:
the build client jar was written to the home root instead of .codenameone/, it
was an empty placeholder when the mojo loads a class out of it, and the build
stopped at "compile" while the css goal that produces theme.res is bound to
process-classes. All six tests pass now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fix the core build, and four defects the review found

The Ant core build compiles against the Codename One runtime, not the JDK, and
StringBuilder.replace(int,int,String) exists in neither vm/JavaAPI nor
Ports/CLDC11 - so build-test (8) and javase-simulator-tests failed on a call
that compiled cleanly on a desktop. The splice now copies front to back with
append and substring. Verified the way CI does it, with
-bootclasspath ../cn1-binaries/CLDC11.jar, and with a negative control that
puts the replace() call back and fails.

Windows paths were wrong for the dotfile hosts. KnownClient.absolutePath
prefixed EVERY Windows entry with %APPDATA%, so Codex resolved to
~/AppData/Roaming/.codex/config.toml when CODEX_HOME is ~/.codex on every
platform - %USERPROFILE% on Windows. Claude Code had the same bug for
~/.claude.json. Both are silent: the config is never found, so the host is
never detected and nothing is ever written. The table now says which base each
host uses; only Claude Desktop, an installed application with a per user
directory of its own, keeps %APPDATA%. appDataPath now takes the home as an
argument instead of reading it back, so a path is a pure function of the home
it is resolved against - the asymmetry the new test caught first.

A multi-line string may legally end in four or five quotes, because the VALUE
itself may end in one or two. Consuming the first three as the delimiter left a
stray quote and refused a valid Codex configuration.

A container has to close with the delimiter it opened with. One depth counter
accepted `value = [}` as balanced, so a file that is not valid TOML was edited
anyway, against the one promise this editor makes. The walk now tracks the
closers it owes. Python's tomllib confirms both premises: it parses the
quote-run document and rejects all three mismatched-delimiter ones.

Removal no longer claims "no matching entries were found" when it does not know
that: a refusal produces the same empty list. It does NOT list the hosts that
were not updated the way Install does, because on removal that set is every
host the tool was never registered with, which would report the normal case as
a failure; the reason is in the code beside the message.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Do not let a neighbour's dotted key, or a no-op install, look like a failure

Registering a second time reported failure. writeTomlEntry treats "the document
did not change" as "nothing was updated", which is right for a removal with no
entry to remove and wrong for a registration whose entry is already exactly
what would be written - the host IS registered. Install then listed Codex under
"Not updated" and pointed at a log that says nothing, on the ordinary path of
clicking Install twice. The check now answers per operation.

A neighbouring server declared with a root dotted key blocked everything. The
refusal was written for `mcp_servers = <value>`, after which TOML forbids a
later [mcp_servers.x] header - but it fired on any root key whose FIRST segment
was mcp_servers, so `mcp_servers.docs.command = "d"` refused both registration
and removal of an unrelated entry. Dotted keys leave mcp_servers defined by
dotted keys, and TOML explicitly allows a [table] header to add a sub-table to
one of those; only the whole-table assignment is fatal, and a dotted key naming
THIS server is already caught as a second declaration of it.

tomllib settles both boundaries: it parses `mcp_servers.docs.command = "d"`
followed by our table, and rejects the same document when the dotted key names
mcp_servers itself or this server. The cross-check now asserts that every
refusal on a valid document is justified by appending being illegal there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Write through an existing config instead of replacing it

Deleting the config and renaming a staged file over it turned a symlinked
config - a common dotfiles arrangement - into a regular file, and reset the
file's mode to whatever the process umask said. Observed, not theorised: on the
previous commit a 600 symlink to ~/dotfiles/codex-config.toml comes back as a
644 regular file and the dotfiles source never sees the change. These files
carry other tools' API keys in their env blocks, so widening a hand-set 600 is
not cosmetic, and it happened on every write rather than on some unlucky one.

An existing config is now written through, which keeps the inode and therefore
keeps both the link and the mode. FileSystemStorage cannot read a link or copy
a mode - it has no API for either - so preserving the original file is the only
portable way to preserve them, and the suggestion to resolve the link or copy
the metadata explicitly cannot be implemented where this code has to live.

Nothing here was atomic to begin with, and the comment claiming it has gone:
rename cannot overwrite on every platform, so the old path deleted first and
had a window where the config was missing entirely. The staged sibling file
remains the recovery path - it holds the complete new content until the write
through succeeds - so the failure story is unchanged while the metadata story
is fixed. This applies to the JSON hosts too; ~/.claude.json holds tokens.

Verified end to end through the real JavaSE port: symlink still a symlink, mode
still 600, neighbouring server's secret env intact, no staging file left
behind, and the codex CLI reads the result and still reads it after removal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Say why CODEX_HOME is not followed, since it cannot be from here

Codex really is relocatable with CODEX_HOME - the review is right about the
behaviour - but the registrar cannot follow it. The Codename One runtime has no
System.getenv: it is absent from ../cn1-binaries/CLDC11.jar, the bootclasspath
the Ant core build compiles against, and from the java-runtime jar the bytecode
compliance check uses, so the call does not compile no matter what a desktop
JVM would do at runtime. Wiring it up would mean a desktop port, which does
have an environment, handing it to core through new public API, which is a
bigger decision than a Codex writer should make on its own.

Worth recording how nearly this went the other way: javap on either jar reports
a getenv that core cannot call, because it resolves java.lang.System from the
JDK rather than from the jar on the classpath. Only javac -bootclasspath tells
the truth, and it is what caught this after the plumbing was already written.
The note in the code says so, so the next reader does not repeat the check and
reach the wrong answer.

The affected user is told instead: the guide now says to add the entry by hand
when CODEX_HOME has moved the configuration, and the code records what such a
machine sees - Codex not detected at all, or a stale ~/.codex updated if one
survived the move.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant