Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 14 additions & 1 deletion .agents/skills/acknowledg-client/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ From `edgacknowledg.client` (`__all__`):
- `ConnectionStatusListener` — `connected` / `attempting_reconnect` /
`disconnected`
- `ReviewClient` (structural **Protocol**): `review_id`, `name`, `timestamp`,
`sections()`, `add_section` / `remove_section`
`sections()`, `add_section` / `remove_section`. `name` is a `RichName`
(segments built with `rich_text` / `rich_link` from `edgacknowledg`; see
PROTOCOL.md "Rich names"); a plain title is `[rich_text(title)]`
- URL/env helpers: `add_endpoint_arguments`, `form_section_http_url`,
`default_*` host/port helpers
- Shared: `BackgroundWorkerPool`, errors
Expand Down Expand Up @@ -79,6 +81,17 @@ Auth header: `X-AcknowlEDG-API-Key` (never put the key in query strings).
`RoleOccupied`: discard that handler / stop reconnecting that section; keep
other sections running.

Batch subscribe / unsubscribe answers are not timed: the server answers at
once, and a lost connection (keepalive pings notice) fails what is pending
as `NotConnectedError`; `add_section` keeps the section registered, and the
next session restores it.

`IncompatibleProtocolVersion` carries the peer's `revision` (the server's
`outdated-proto` says its own) and `peer_is_newer`. It stops a session;
`BatchClient(wait_for_server_update=True)` instead waits out an older
server, reconnecting every `SERVER_UPDATE_RETRY_S` (5 s) with its sections
still registered. A newer server still stops it: the client must be updated.

## Batch subscription maps

`_BatchClientReview` tracks:
Expand Down
103 changes: 103 additions & 0 deletions .agents/skills/edg-agent-temp-files/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
name: edg-agent-temp-files
description: >-
Where agents put temporary files and directories (scratchpad, the project's
.tmp/agent-* directory, or the container's /tmp), how to share them with the
docker container via edg-exec, and how to run edgy ad hoc with --runs-dir
(and a scratch EDG_TEST_HOME) instead of edg-docker-test. Use when creating
scratch inputs or outputs, running throwaway tests or recordings, or cleaning
up temporary state.
---

# Temporary state and the docker boundary

Tools run either on the host or in the docker container (`edg-exec`). The
container sees **only the project root**, mounted at `/edg/workspace`; the host
`/tmp` and your scratchpad are not visible to it. Project root = directory
containing `src/cfe.c` and `dev_tools/`.

## Where to put temporary state

| Need | Put it in | Notes |
| --- | --- | --- |
| Host-only (scripts, outputs of host tools) | your scratchpad directory | no permission prompts |
| Shared with the container | `<root>/.tmp/agent-<purpose>` | seen as `/edg/workspace/.tmp/agent-<purpose>`; `.tmp/` is gitignored |
| Only needed inside the container | the container's `/tmp` | ephemeral, nothing is left on the host |

- Everything you create in `.tmp/` **must** be named `agent-<purpose>` (the
rest of `.tmp/` is the user's host-to-docker bridge; see `.tmp/README.md`).
- Do not use `build/`, `tests/runs/`, or the host `/tmp` for scratch state.
- Files created in the container are owned by the host user, so they are
directly usable from the host.

## edg-exec rules

- Run `edg-exec` from the project root (the current directory is mounted as
`/edg/workspace`).
- `edg-exec` joins its arguments with spaces and **does not preserve
quoting**: `edg-exec -- sh -c '. env.sh; cmd'` runs `sh -c .` and drops the
rest. Pass a compound command as ONE quoted string:

```bash
edg-exec -- "mkdir -p .tmp/agent-foo && echo hi > .tmp/agent-foo/x"
edg-exec --dry-run -- "..." # shows exactly what the container will run
```

- `edgy` and the other `dev_tools/bin` tools are on the container `PATH`.

## Running edgy outside the standard workflow

`edg-docker-test` is for the standard front-end change workflow, where the
user wants results kept in `tests/runs/` (see **edg-cpfe-build-test**). For
anything else (experiments, verification of tooling, comparisons), run `edgy`
with `--runs-dir` so nothing lands in `tests/runs/`:

```bash
# In docker: results appear on the host under .tmp/agent-foo/runs/<timestamp>/
edg-exec -- ". build/gcc/environment.sh && edgy --runs-dir=/edg/workspace/.tmp/agent-foo/runs regressions/foo.sft.cpp"
```

- `. build/<dir>/environment.sh` provides `CPFE`/`CPFE_CP`, which `edgy` uses
to find the front end (use the build directory you are testing). The default
configs need both `cpfe` and `cpfe-cp` built; `-c edg_x86_64` runs the C
config alone.
- Use an **absolute** container path for `--runs-dir`. `edgy` copies the front
end under the runs directory and a relative path breaks tools that change
directory (e.g. `cpfe-cp-gen-be` fails with "No such file or directory").
- Host-side tools that take `--runs-dir` (e.g. `edg-rematerialize-test-run`)
have no docker constraint: point them at the scratchpad.
- If `edg-docker-test` is still used for a throwaway run, pass
`--discard-test-results` (results stay in the container's `/tmp`).

## Scratch test home (for `-W` and other mutating experiments)

`edg-docker-test` does not forward a host `EDG_TEST_HOME`, but setting it
**inside** the container command works. Build a small test home and point at
it; never run `-W` against the real tree:

```bash
H=.tmp/agent-foo/home
mkdir -p $H/tests
cp -r tests/.edgy $H/.edgy
cp -r tests/expectations $H/expectations
cp -r tests/tests/<suite> $H/tests/<suite> # only the suites you need
CMD='. build/gcc/environment.sh && EDG_TEST_HOME=/edg/workspace/.tmp/agent-foo/home edgy --runs-dir=/edg/workspace/.tmp/agent-foo/runs <suite>/<test>'
edg-exec -- "$CMD" # read-only first: logs must land under .tmp/agent-foo
edg-exec -- "${CMD/edgy /edgy -W }" # then record (expectations and .rto files in the scratch home only)
```

Check `git status --short tests` and that `tests/runs/` did not gain an entry.

## Cleanup

- Remove the `.tmp/agent-*` paths **you created** in a batch step as the LAST
step before reporting results to the user (not after each sub-task), in ONE
command that lists them (one approval instead of many):

```bash
rm -rf .tmp/agent-foo .tmp/agent-bar
```

- Never glob other entries, never remove non-`agent-` names in `.tmp/`, and
do not delete `tests/runs/` content (it is gitignored and may be the user's).
- Say in the final summary what you created and removed.
93 changes: 79 additions & 14 deletions .agents/skills/edg-changes-example/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
---
name: edg-changes-example
description: >-
Encodes and decodes non-UTF-8 example bytes in Changes changelogs with
edg-changes-example («HHHH...» markers) and writes Changes files as UTF-8.
Use when editing any Changes file (src/Changes, util/Changes, …), adding
Writes Changes entries as pending_changes/*.txt files (collected
nightly by edg-collect-changes, checked with edg-collect-changes --check),
and encodes/decodes non-UTF-8 example bytes with edg-changes-example
(«HHHH...» markers). Use when adding a Changes entry, editing any Changes
file (src/Changes, util/Changes, …) or pending_changes/ entry, adding
examples with Latin-1/EUC-JP/Shift-JIS/other non-UTF-8 bytes, or verifying
changelog encoding.
---

# `edg-changes-example` and Changes files
# Changes entries, `edg-collect-changes`, and `edg-changes-example`

## Policy (all `Changes` files)

Expand Down Expand Up @@ -64,16 +66,60 @@ To rebuild the real example bytes (for local reproduction, not for commit):
```bash
edg-changes-example decode utf8-fragment.txt > raw-fragment.txt
edg-changes-example decode -o raw-fragment.txt utf8-fragment.txt
# Whole file:
edg-changes-example decode src/Changes > /tmp/Changes.raw
# Whole file (write host-only output to your scratchpad, see
# edg-agent-temp-files):
edg-changes-example decode src/Changes > <scratchpad>/Changes.raw
```

Decode replaces each `«HHHH…»` (or legacy `«HH»«HH»`) with the corresponding
bytes. No other escapes are interpreted.

## Workflow for a new changelog entry

1. Draft the entry as UTF-8 prose.
New entries are **not** written into a `Changes` file. Each `Changes` file
has a `pending_changes/` directory beside it (`src/pending_changes/`,
`util/pending_changes/`, …); add one entry file there per change, named
`*.txt` (suggested: `gh-<N>-<short-slug>.txt`). A nightly job
(`.github/workflows/collect-changes.yml`, midnight US Eastern) runs
`edg-collect-changes`, which moves every entry into its `Changes` file under
the newest `Version x.y` line, adds the date, orders that night's entries by
summary line, and deletes the entry files.

Entry file format:

```text
//allowed_words: reflectable memoized
[GH #335]
Type transformations of qualified function types

Previously, the __add_lvalue_reference, __add_rvalue_reference, ...
For example, with --c++11:

using F = void() const;
using F = __add_pointer(F); // Previously a spurious error, now okay.
```

- Optional leading `//key: value` directives (EDG C++ line directive
syntax). `//allowed_words:` lists space-separated words the spell check
should accept (identifiers, jargon); repeat the line as needed. Words the
target `Changes` file already uses (`constexpr`, `lvalue`, …) are accepted
without it. Directives are dropped when the entry is collected.
- The tag block: one or more comma-separated `GH #N` tags in brackets
(`[GH #12,GH #34]`; only `GH #N`, never `[]`). It may wrap onto several
lines; the tool re-wraps it the way existing entries are wrapped.
- **No date.** The tool adds it (`m/d/yy`, padded to 8 columns) in front of
the tags.
- The summary line, one blank line, then the description, in the same style
as existing entries (unindented prose wrapped at 79 columns, two spaces
after periods, examples indented 2 spaces).
- UTF-8, no tabs, at most **79** columns per line. Trailing whitespace is
tolerated (it's stripped on collection).

Steps:

1. Draft the entry as UTF-8 prose in
`<dir>/pending_changes/<name>.txt` (the `pending_changes/` beside
the `Changes` file the entry belongs in, usually `src/`).
2. If an example needs non-UTF-8 bytes, author the example in a small raw
file (or produce the markers by hand only when the bytes are already
known), then run `edg-changes-example encode` and paste the UTF-8 result
Expand All @@ -82,20 +128,39 @@ bytes. No other escapes are interpreted.

`Note: The above example must be decoded using the edg-changes-example tool.`

4. Insert the entry into the appropriate `Changes` file with a **UTF-8**
write (keep the rest of the file valid UTF-8).
5. Verify the file still decodes as UTF-8 (raises on failure):
4. Check the entry (format, spelling, typos, line length). This is the
check `edg-check-file-changes` does for `pending_changes/*.txt` files,
which pull request CI runs and which makes the pre-push hook refuse the
push (no override) if anything is wrong:

```bash
python3 -c "open('path/to/Changes', encoding='utf-8').read()"
edg-exec -- edg-collect-changes --check src/Changes src/pending_changes
```

Use the real path (for example `src/Changes`). A clean exit means the
whole file is valid UTF-8; a `UnicodeDecodeError` means the write
introduced non-UTF-8 bytes and must be fixed before continuing.
(Name the `Changes` file and `pending_changes/` directory the entry is
in. `edg-exec` runs it in the dev-env container, which has `aspell`.) For
misspellings that are really identifiers or terms, add them to an
`//allowed_words:` line at the very top of the entry, as the failure
message shows; fix real misspellings instead. `edgspelling.preprocess`
leaves an identifier like `getXValue` whole because it contains a
one-letter part. If aspell reports such an identifier whole, add the
whole identifier to `//allowed_words:`; adding only its parts (`get`,
`X`, `Value`) will not suppress the warning.
5. Optionally preview the result without changing anything:
`edg-collect-changes --dry-run src/Changes src/pending_changes`.

Edit a `Changes` file directly only to correct an entry that has already
been collected; then write it as **UTF-8** and verify the file still decodes
(raises on failure):

```bash
python3 -c "open('path/to/Changes', encoding='utf-8').read()"
```

## Do not

- Add new entries directly to a `Changes` file, or put a date in a
`pending_changes/` entry.
- Commit raw Latin-1 / Shift-JIS / etc. bytes inside a `Changes` file.
- Invent alternate note wording; match the existing sentence above.
- Run `encode` on the entire historical `src/Changes` and rewrite it unless
Expand Down
132 changes: 132 additions & 0 deletions .agents/skills/edg-cmakedef-build-config/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
name: edg-cmakedef-build-config
description: >-
Explains EDG macro/build configurations: the .cmakedef files under
cmake/macro-conf, the edg-cmakedef resolver, EDG_MACRO_CONF selection, and
CMakePresets.json. Use when adding or changing a macro for a build, creating
a new configuration or variant, finding out why a macro is (not) set, or
choosing a preset. For running builds and tests, use edg-cpfe-build-test.
---

# EDG cmakedef build configurations

A **macro configuration** is a named set of `.cmakedef` files that decide
which preprocessor macros each binary is compiled with. CMake resolves them
with `dev_tools/bin/edg-cmakedef`. Project root = directory containing
`src/cfe.c` and `dev_tools/`.

Source of truth (read these rather than trusting this summary):

- `dev_tools/bin/edg-cmakedef` — the resolver / language.
- `cmake/macro-conf.cmake` — CMake glue.
- `cmake/host-defaults.cmake` — auto-selection when nothing is specified.
- `cmake/macro-conf/` — the configurations.
- `CMakePresets.json` — presets that pick a configuration.

## The cmakedef language

One statement per line; blank lines and `#` comments are ignored.

| Line | Meaning |
| --- | --- |
| `NAME` | define `NAME` (emitted as `NAME=1` in `#define` output) |
| `NAME=value` | define with a value (may be empty) |
| `import <dir/file>` | process `cmake/macro-conf/dir/file.cmakedef` here (root-relative, no extension) |
| `delete NAME` | remove a prior definition; **error** if not set |
| `delete_if_set NAME` | remove a prior definition; message only if not set |

- Later lines override earlier ones (including across imports), so order
matters: import the base first, then add overrides.
- `@VAR@` in a value is expanded by CMake (`string(CONFIGURE)`).
- Any unparsable line or failing `delete` makes the file invalid; the
CMake configure then fails with "Failed to process cmakedef."

## Layout of `cmake/macro-conf/`

- `<config>/<target>.cmakedef`, one file per target. Targets and who reads
them: `base` (`src/CMakeLists.txt`, emitted as a generated
`cmake_defines.h` plus `USE_CMAKE_DEFINES`), `cpfe`, `cpfe-cp`, `cdisp`
(`src/cmake/<target>/CMakeLists.txt`) and `cpprtlib`
(`lib_src/CMakeLists.txt`); the last four become `-D` flags.
- `default/` — baseline each config imports first
(e.g. `default/cpfe` sets `BACK_END_IS_C_GEN_BE`, `DO_IL_LOWERING`).
`default/base.cmakedef` is a "should not be used" stub.
- `support/` — reusable fragments: `platform/`, `arch/`, `compiler/`,
`build-type/`, `simple-conf/`, `feature/` (`on`/`off`), `target/`.
Fragments are per-target too (e.g. `support/build-type/debug/cpfe`).
- Named configs (`linux-gcc`, `linux-gcc-release`, `linux-clang`,
`linux-i686-gcc`, `macos-arm-clang`, `windows-msvc`, …). Variants layer on
a parent: `linux-gcc-multi-thread-release/cpfe.cmakedef` imports
`<linux-gcc-release/cpfe>` and then appends its own macros.
- A config directory missing a target file is auto-populated by CMake with
`import <default/<target>>`; don't rely on that for real configs.

## Selection

- Single-config generators (Ninja): cache var `EDG_MACRO_CONF`.
- Multi-config generators: `EDG_DEBUG_MACRO_CONF` and
`EDG_RELEASE_MACRO_CONF`.
- If empty, `host-defaults.cmake` picks one from OS, arch, compiler, and
build type (`detect_host_defaults`); otherwise CMake warns.
- Presets set it explicitly, e.g. `linux-gcc-debug` →
`EDG_MACRO_CONF=linux-gcc`, binary dir `build/gcc`.
- Every cmakedef file reached is added to `CMAKE_CONFIGURE_DEPENDS`, so
editing one re-runs configure on the next build.

## Recipes

Inspect what a config resolves to (host Python, read-only, no build):

```bash
edg-cmakedef cmake/macro-conf linux-gcc/cpfe.cmakedef print-values
edg-cmakedef --verbose cmake/macro-conf linux-gcc/cpfe.cmakedef print-values
edg-cmakedef cmake/macro-conf linux-gcc/base.cmakedef print-defines
edg-cmakedef cmake/macro-conf linux-gcc/cpfe.cmakedef print-paths
```

- The target is resolved against the root if relative (CMake passes
absolute paths); never repeat the root in it.
- `print-values` → `NAME=value` lines; `print-defines` → `#ifndef/#define`
blocks (the `base` form); `print-paths` → the files visited.
- `--verbose` writes the import chain and each Setting / Overwriting /
Deleting step to **stderr**, which shows exactly which file last set a
macro. Use it to answer "why is X set?".
- Compare two configs by diffing the `print-values` output (sort first).

Change a macro for one build: edit the narrowest file that covers it.
Shared by everything → `default/<target>`; one platform / build type /
compiler → the matching `support/…` fragment; one named config or variant →
that config's `<target>.cmakedef`. Check all targets that need it
(`base` vs `cpfe` vs `cpprtlib` are separate files).

Add a new configuration:

1. Copy the nearest sibling directory under `cmake/macro-conf/` with all
its target files; keep imports of `default/` and `support/` fragments.
2. If it is a variant, import the parent's file instead of copying it.
3. Add a preset to `CMakePresets.json` (inherit `linux-common` or the
platform's common preset; set `EDG_MACRO_CONF`, `binaryDir`).
4. If it should be auto-selected, add a branch in
`cmake/host-defaults.cmake` (and note release builds use the
`<name>-release` directory).
5. Validate with the `print-values` recipe for every target, then
configure/build in Docker (see **edg-cpfe-build-test**):

```bash
edg-exec -- cmake --preset <preset>
edg-exec --wdir build/<dir> -- ninja
```

## Pitfalls

- `import <…>` paths are relative to `cmake/macro-conf`, with no extension.
- `delete` of a never-set key fails the configure; use `delete_if_set` when
the key might legitimately be absent.
- A macro in a cmakedef only matters if the source consumes it; the generated
`cmake_defines.h` is only used when `USE_CMAKE_DEFINES` is set. Editing
`src/defines.h` (BUILD.md) does not change what a CMake configuration
produces.
- `print-paths` output order is unspecified (set iteration).
- Windows uses `dev_tools/win-bin/edg-cmakedef.bat`; the Python is
type-checked by `dev_tools/typecheck-python.sh` (follow
**edg-python-style** if editing the tool).
Loading