|
1 | 1 | --- |
2 | 2 | name: records |
3 | | -description: Commit records and review pages for the ReScript compiler repository. Use when committing a change, when an agent reports its work, and when someone asks to review a commit, a pull request or a branch. Every commit message is a structured record that answers the questions ReScript reviewers ask; review pages are rendered from records with scripts/commitRecords.js, never written by hand. |
| 3 | +description: Commit records and Semantic Diff pages for the ReScript compiler repository. Use when committing a change, when an agent reports its work, and when someone asks to review a commit, a pull request or a branch. A commit message describes what the commit changes in the form suited to it (trees, code, diagnostics, typing rules, clause matrices, representations) Before and After; scripts/commitRecords.js renders the messages as a Semantic Diff page, one card per commit drawing its message. |
4 | 4 | --- |
5 | 5 |
|
6 | | -# Commit records and review pages |
| 6 | +# Commit records |
7 | 7 |
|
8 | | -A **record** is a commit message whose body has named prose sections and |
9 | | -whose last block is git trailers. Its fields are the questions reviewers of |
10 | | -this repository ask on pull requests, answered before they are asked. A |
11 | | -review page is rendered from records: one card per commit, and for a range a |
12 | | -summary, a changelog draft and the files more than one commit changes. |
| 8 | +A record is a commit message that describes what the commit changes, each |
| 9 | +change in the form suited to what it changes: a parse tree or typed tree as |
| 10 | +the tree before and after, Lambda and generated JavaScript as code before |
| 11 | +and after, a diagnostic as its text, a typing rule as an inference rule, |
| 12 | +the match compiler's split as a clause matrix, a runtime representation as |
| 13 | +a mapping. `scripts/commitRecords.js` renders records as a Semantic Diff |
| 14 | +page, one card per commit, drawing each form in its own way, Before and |
| 15 | +After side by side. |
13 | 16 |
|
14 | | -## The record |
| 17 | +## The message |
15 | 18 |
|
16 | 19 | ``` |
17 | | -<subject: present tense, what the compiler or tool now does> |
18 | | -
|
19 | | -<one paragraph: the change at the level of the language or the tool> |
20 | | -
|
21 | | -Example (rescript): |
22 | | - <the ReScript source that shows the change, at most 15 lines> |
23 | | -
|
24 | | -Before (js): |
25 | | - <generated JavaScript before, for that source> |
26 | | -
|
27 | | -After (js): |
28 | | - <generated JavaScript after> |
29 | | -
|
30 | | -Source: <how the Before/After JavaScript was produced: compiler and revision, |
31 | | -or the snapshot file in the diff> |
32 | | -
|
| 20 | +<subject: what the compiler or tool does, present tense> |
| 21 | +
|
| 22 | +Why: |
| 23 | + <the problem the change solves> |
| 24 | +
|
| 25 | +AST modified (raw extensions): |
| 26 | +Example: |
| 27 | + let f = %raw(`(a) => a`) |
| 28 | +Before (parse): |
| 29 | + structure_item |
| 30 | + Pstr_value Nonrec |
| 31 | + <def> |
| 32 | + pattern |
| 33 | + Ppat_var "f" |
| 34 | + expression |
| 35 | + Pexp_extension "raw" |
| 36 | +After (parse): |
| 37 | + structure_item |
| 38 | + Pstr_value Nonrec |
| 39 | + <def> |
| 40 | + pattern |
| 41 | + Ppat_var "f" |
| 42 | + expression |
| 43 | + Pexp_raw "raw" |
| 44 | + Raw_template "(a) => a" |
| 45 | +
|
| 46 | +Review: <a question a reviewer asks, and its answer> |
33 | 47 | Breaking: <what existing code or tooling stops working, and the migration> |
34 | 48 |
|
35 | | -Review: <a question a reviewer raised or will raise, and its answer; repeat> |
36 | | -
|
37 | | -Area: syntax printer frontend typechecker lambda codegen runtime rewatch |
38 | | - analysis reanalyze gentype tools playground scripts ci docs tests |
39 | | -Output: unchanged | changed <which programs>, <evidence> |
40 | | -Formatting: unchanged | changed <which source shapes> |
41 | | -Formats: none | <bumped magic numbers: ast cmi cmt cmj> |
42 | | -PPX: unchanged | <effect on the frozen v0 PPX wire> |
43 | | -Editor: unchanged | <effect on completion, hover, hints; fixtures> |
44 | | -Tests: +added/path ~updated/path -removed/path | none, because <reason> |
45 | | -Measured: <quantity before -> after, and what produced it>; ... |
46 | | -PR: #<number> |
47 | | -Signed-off-by: <Name> <email> |
| 49 | +Signed-off-by: Name <email> |
48 | 50 | ``` |
49 | 51 |
|
50 | | -- **Prose sections** are a line `Name:` or `Name (lang):` followed by text or |
51 | | - a block indented by 4 spaces. `lang` is `rescript`, `js`, `ts`, `sh`, |
52 | | - `rust`, `ocaml` or `text`; the renderer highlights ReScript and JavaScript. |
53 | | - `Before` and `After` sections of one language render side by side with |
54 | | - changed lines marked. Use `Before (rescript)` / `After (rescript)` for a |
55 | | - formatter change and `Diagnostic (text)` for compiler output. Any other |
56 | | - name is allowed and renders as prose or code. |
57 | | -- **The final block is git trailers**: `Key: value` lines, continuation lines |
58 | | - indented by one space, nothing after them. `git interpret-trailers --parse` |
59 | | - must read every key. `Signed-off-by` (DCO) is required on every commit. |
60 | | -- **No changelog in the record**: the `changes/<name>.<category>.md` |
61 | | - fragment the commit adds is the single source of truth for its changelog |
62 | | - category and entry (see `changes/README.md`). The record repeats neither; |
63 | | - the review page reads the fragment from the diff. |
64 | | -- **Required keys**: `Area`, `Output`, `Tests`. `Formatting`, `Formats`, |
65 | | - `PPX` and `Editor` are required whenever the change touches the syntax |
66 | | - library, the parsetree, the typed tree or Lambda. Omit the others when they |
67 | | - do not apply. |
68 | | -- **Wording** follows the writing rules: present facts, positive statements, |
69 | | - claims as strong as their evidence, every number labelled by what produced |
70 | | - it. A JavaScript `Before`/`After` pair says where it came from in a |
71 | | - `Source:` paragraph (compiler run, or a snapshot file in the diff). |
72 | | -- **Lists in trailers**: `Measured` separates items with `; ` |
73 | | - (outside parentheses); each item renders on its own line. `Output` and the |
74 | | - other state trailers start with their state word (`unchanged`, `changed`, |
75 | | - `none`), followed by the detail. |
76 | | - |
77 | | -## What each field states |
78 | | - |
79 | | -| Field | What the record states | |
| 52 | +- The subject and `Signed-off-by` are required. The message ends with its |
| 53 | + trailers, git's `Key: value` lines (`Co-Authored-By:`, `Fixes:` or any |
| 54 | + other one-word key), `Signed-off-by` last; the page lists the |
| 55 | + `Co-Authored-By` names and draws no other trailer. Every section is |
| 56 | + optional. |
| 57 | +- A section starts at a line `Why:`, `Review:`, `Breaking:`, an object |
| 58 | + block's heading, an `Example:` alone on its line, or a `Before (<form>):` |
| 59 | + or `After (<form>):` heading, and holds the text after its colon and the |
| 60 | + block indented by 4 spaces or more under it; a blank line ends a section |
| 61 | + that holds only text. `Review:` repeats, one question each. Every other |
| 62 | + line is prose, and a block indented by 4 spaces outside a section is |
| 63 | + ReScript code. Tabs count as 4 columns. |
| 64 | +- An **object block** is a heading `<Kind> added|modified|removed (<object>):`, |
| 65 | + the kind one capitalised word naming the object, then an optional |
| 66 | + `Example:` with a ReScript program indented by 4 spaces, then the |
| 67 | + object's forms, each version a `Before (<form>):` or `After (<form>):` |
| 68 | + heading with its content indented by 4 spaces. Text after the colon of a |
| 69 | + `Before`/`After` heading captions the block under it, or is the version |
| 70 | + itself when no block follows (`After (js): return x;`). A heading that |
| 71 | + leaves out the object's parentheses is drawn as its action and kind. |
| 72 | +- A block draws the versions it has: a form with both versions side by |
| 73 | + side, or once, with the captions, when the two are equal; a form with |
| 74 | + one version across the block under its version's label. Trees, code, |
| 75 | + text, matrices and mappings are drawn on aligned rows, a line common to |
| 76 | + both versions facing itself and the changed lines shaded; typing rules |
| 77 | + and rewrites are drawn as two figures side by side, the changed parts |
| 78 | + shaded: premises, conclusions, rule names and formulas, and each term of |
| 79 | + a rewrite against the term at its position. |
| 80 | +- The changelog entry is the `changes/<name>.<category>.md` fragment the |
| 81 | + commit adds (`changes/README.md`). |
| 82 | + |
| 83 | +## Kinds |
| 84 | + |
| 85 | +The table lists the common kinds. |
| 86 | + |
| 87 | +| Kind | Object | |
80 | 88 | | --- | --- | |
81 | | -| `Area` | The layers the change touches. They decide who reviews it and which suites apply; a parsetree or typed-tree change also reaches editor analysis. | |
82 | | -| `Output` + `Before`/`After (js)` | The generated JavaScript for the example before and after, and which existing programs compile differently. `unchanged` holds when no committed generated JS changes, or when a rebuild of the test suites is byte-identical. | |
83 | | -| `Formatting` + `Before`/`After (rescript)` | Whether `rescript format` rewrites existing code, and whether formatted output parses back to the same tree with its comments. | |
84 | | -| `Formats` | The magic numbers bumped in `compiler/ext/config.ml`. Any change to the marshaled parsetree, typed tree (`.cmi`, `.cmt`) or `.cmj` layout, constructor order included, bumps the matching number. | |
85 | | -| `PPX` | The effect on the frozen v0 PPX wire: `parsetree0.ml` is unchanged, and a change to the v0 mapping comes with an ast-mapping fixture. | |
86 | | -| `Editor` | Completion, hover and inlay hints on new or changed nodes, and the analysis fixtures that cover them. | |
87 | | -| `Tests` | The tests added, changed or removed, each observing the effect the record claims, so that it fails without the change. `none, because …` gives the reason when no test changes. | |
88 | | -| `Measured` | Performance before and after, with the input and the command that produced each number. | |
89 | | -| `Breaking` | What existing code or tooling stops working, and the migration. | |
90 | | -| `Review` | Questions a reviewer raised or will raise, with their answers. | |
91 | | -| `PR` | The pull request; the renderer links it. | |
92 | | -| `Signed-off-by` | The DCO sign-off, with the commit author's name and email, as the last trailer. | |
| 89 | +| `AST` | a parsetree node | |
| 90 | +| `Typedtree` | a typed tree node | |
| 91 | +| `Typing` | a typing rule | |
| 92 | +| `Matching` | the pattern match compiler's split | |
| 93 | +| `Lambda` | a Lambda term or pass | |
| 94 | +| `JS` | generated JavaScript | |
| 95 | +| `Diagnostic` | an error or warning | |
| 96 | +| `Format` | the formatter's output | |
| 97 | +| `Representation` | how a value is represented in JavaScript | |
| 98 | + |
| 99 | +## Forms |
| 100 | + |
| 101 | +| Form | Content | Drawn as | |
| 102 | +| --- | --- | --- | |
| 103 | +| `parse` | the parse tree | tree | |
| 104 | +| `expanded` | the parse tree after the built-in PPX | tree | |
| 105 | +| `typed` | the typed tree | tree | |
| 106 | +| `lambda` | Lambda | highlighted code | |
| 107 | +| `js` | the generated JavaScript | highlighted code | |
| 108 | +| `rescript` | ReScript source, such as the formatter's output | highlighted code | |
| 109 | +| `diagnostic` | what the compiler reports | text | |
| 110 | +| `text` | any text | text | |
| 111 | +| `rule` | inference rules and formulas | inference rule | |
| 112 | +| `matrix` | a clause matrix | matrix | |
| 113 | +| `representation` | how ReScript values map to JavaScript | mapping | |
| 114 | + |
| 115 | +- A tree is indented lines, two spaces a level, as the compiler prints it: |
| 116 | + `bsc -bs-no-builtin-ppx -only-parse -dparsetree file.res` prints the |
| 117 | + parse tree, `bsc -only-parse -dparsetree` the expanded one, and |
| 118 | + `bsc -dtypedtree` the typed tree. |
| 119 | +- Code is highlighted in its language; `bsc -drawlambda` prints the Lambda. |
| 120 | + Code can be a rewrite: each `⇝` separates the code before it from the |
| 121 | + code after it (`lhs ⇝ rhs` or a chain `a ⇝ b ⇝ c` on one line, or `⇝` |
| 122 | + alone on a line), and `label: formula` lines after the last term are its |
| 123 | + side conditions. |
| 124 | +- A `rule` group is premises, a bar of `─` with the rule's name in |
| 125 | + parentheses, and the conclusion; any other group is formulas, one a |
| 126 | + line. Groups are separated by blank lines, side-by-side formulas by three |
| 127 | + or more spaces. One-letter names, with their primes, are italic |
| 128 | + variables, `_x`, `_{…}` and `^{…}` sub- and superscripts, and `code` in |
| 129 | + backticks is ReScript. |
| 130 | +- A `matrix` is one row a line, columns three or more spaces apart, each |
| 131 | + cell a pattern; `label: text` lines are notes under it. |
| 132 | +- A `representation` is `ReScript ↦ JavaScript` lines; `label: text` lines |
| 133 | + are notes among them. |
| 134 | +- A form of another name is drawn as text. |
| 135 | + |
| 136 | +## When to add a block |
| 137 | + |
| 138 | +A commit gets one object block for each object it changes, with the |
| 139 | +smallest example that shows the change. A refactor, a test, a script or a |
| 140 | +review fix is a subject and a line or two of prose. |
93 | 141 |
|
94 | 142 | ## Rendering |
95 | 143 |
|
96 | 144 | ```sh |
97 | | -node scripts/commitRecords.js --out review.html <rev>... |
98 | | -node scripts/commitRecords.js --out review.html <base>..<branch>... |
99 | | -node scripts/commitRecords.js --fragment --out part.html <rev>... |
100 | | -node scripts/commitRecords.js --out review.html --pr 1234 --title "<PR title>" <base>..<branch> |
| 145 | +make semantic-diff # master..HEAD to _build/semantic-diff.html, opened |
| 146 | +node scripts/commitRecords.js --out page.html [--pr <number>] [--title <text>] \ |
| 147 | + <rev | base..tip>... |
101 | 148 | ``` |
102 | 149 |
|
103 | | -- `--pr` and `--title` head the page with the pull request's number (linked) |
104 | | - and title; without them the page is headed "Semantic Diff". |
105 | | - |
106 | | -- A revision renders one card. A range renders a summary row, a changelog |
107 | | - draft grouped by category, its commits as cards, and the files more than |
108 | | - one commit (or more than one range) changes. The changelog category, the |
109 | | - entries and the draft come from the `changes/` fragments in the diff: a |
110 | | - card shows the fragments its commit adds or changes, and a range's draft |
111 | | - shows the fragments the range leaves, in their last version. |
112 | | -- Each card checks the record against its diff: a `changes/` fragment that |
113 | | - `yarn changelog:check` rejects (such as one still carrying the placeholder |
114 | | - PR link), an edit to `CHANGELOG.md`, modified generated `.mjs`, `.cjs` and `.res.js` files under |
115 | | - `Output: unchanged` (new ones from new tests are counted, not flagged), a |
116 | | - magic number bumped in `compiler/ext/config.ml` that |
117 | | - `Formats` does not name, a parsetree change with no ast-mapping fixture, a |
118 | | - missing `Tests` trailer, `Tests: none` on a diff that changes tests. A failed |
119 | | - check is shown on the card. The DCO app checks `Signed-off-by`. |
120 | | -- The page is one self-contained HTML file: no script, no external data |
121 | | - (fonts fall back to system faces), light and dark themes, phone width. |
122 | | - `--fragment` omits the document skeleton for embedding. |
123 | | -- A note on `refs/notes/records` replaces the commit message's record. Use it |
124 | | - for commits that exist already (history, a squash merge) and for review |
125 | | - outcomes added later; a new commit carries its record in its message. |
126 | | - |
127 | | -## When to use |
128 | | - |
129 | | -- Every commit an agent makes carries a record in its message. |
130 | | -- An agent's report lists its commits and the rendered page; the records are |
131 | | - the description of the work. A pull request description is a rendering of |
132 | | - its range. |
133 | | -- Before review or merge: render `master..<branch>` and hand over the page. |
134 | | -- On GitHub, `.github/workflows/semantic_diff.yml` renders each pull |
135 | | - request's range when it is opened or pushed, and comments the page's link |
136 | | - (`Semantic diff: https://cdn.rescript-lang.org/semantic-diff/pr-<N>/…`). |
| 150 | +- `--pr` and `--title` head the page with the pull request. |
| 151 | + `.github/workflows/semantic_diff.yml` renders each pull request's range |
| 152 | + and comments the page's link. |
| 153 | +- In prose, `#1234` and full pull request and issue URLs link as `#1234`, |
| 154 | + and the 9-character short sha of a commit on the page links to its card. |
| 155 | + |
| 156 | +## What the page shows |
| 157 | + |
| 158 | +The page is the heading, then a card per commit. A card shows the commit's |
| 159 | +short sha, author and date, the pull request a `(#1234)` at the end of the |
| 160 | +subject names, and the message drawn: the subject, the prose, each object |
| 161 | +block with its example and forms, the `Breaking:` sections as banners, the |
| 162 | +`Review:` sections as a list, and the co-authors. |
0 commit comments