3
0
mirror of https://github.com/larvit/adf-codec.git synced 2026-11-12 11:48:29 +01:00

Answer product-owner round 1: 0 🔴, 1 🟡 (0 misread); the README names the memory a mutation run needs, and a RuntimeError lists its mutants and the likely cause

This commit is contained in:
2026-10-28 20:21:29 +01:00
committed by Lillem4n
parent 141db21216
commit fac55a8a63
7 changed files with 32 additions and 25 deletions
-2
View File
@@ -117,8 +117,6 @@ holes through each other's lines.
generators and run parameters properties share live in `src/conformance/property-harness.ts`,
outside the build and coverage.
A review mutation-tests a chunk with `mutation-tests/run.sh` rather than setting Stryker up by hand.
Each `- ` bullet in `spec/flavour.md`'s `## Block nodes`, `## Inline nodes` and `## Marks` declares
the nodes named before its first em dash, with the attributes following `Attributes: ` — a
parenthesized value set reading `string`; fenced examples are skipped. Keep prose out of a bullet.
+4 -4
View File
@@ -731,10 +731,10 @@ Contract: [`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/do
Both commands need only Docker, git and bash 5.
- `./ci.sh` runs the gate: every check CI runs.
- `./mutation-tests/run.sh [<base>]` mutation-tests the source lines changed since `<base>`,
`origin/main` by default, running each mutant against only the test files that reach it. It lists
the mutants that survived, and fails only when a mutant's test run crashed.
- `./ci.sh` runs every check CI runs.
- `./mutation-tests/run.sh [<base>]` mutation-tests the lines changed since `<base>`, `origin/main`
by default, in source files git tracks. It needs 6 GB of memory for Docker, and lists the mutants
that survived. Survivors don't fail it; a mutant whose test run crashed does.
## Links
+2 -2
View File
@@ -489,11 +489,11 @@ nodes that break it.
## Stryker in its own package
2026-10-28, item 152. Code health: the code is easy to change safely. Valid while the gate runs no
2026-10-28, the architecture review. Code health: the code is easy to change safely. Valid while the gate runs no
mutation tests.
Mutation testing with Stryker lives in `mutation-tests/`'s own package, so the gate's `npm ci` never
installs it. CI does not run it, so Renovate does not automerge its bumps.
installs it.
## Any ES2022 engine
+6 -4
View File
@@ -1,9 +1,11 @@
import { readFileSync } from 'node:fs'
import config from './stryker.config.mjs'
const mutants = Object.values(JSON.parse(readFileSync(config.jsonReporter.fileName, 'utf8')).files).flatMap((file) => file.mutants)
const errors = mutants.filter((mutant) => mutant.status === 'RuntimeError').length
if (errors > 0) {
console.error(`${errors} of ${mutants.length} mutants ended as RuntimeError, so each may hide a survivor`)
const files = Object.entries(JSON.parse(readFileSync(config.jsonReporter.fileName, 'utf8')).files)
const mutants = files.flatMap(([path, file]) => file.mutants.map((mutant) => ({ ...mutant, path })))
const errors = mutants.filter((mutant) => mutant.status === 'RuntimeError')
if (errors.length > 0) {
console.error(`${errors.length} of ${mutants.length} mutants ended as RuntimeError, so each may hide a survivor. A test run killed for lack of memory ends so:`)
for (const mutant of errors) console.error(` ${mutant.path}:${mutant.location.start.line} ${mutant.mutatorName}`)
process.exit(1)
}
+2 -2
View File
@@ -5,7 +5,7 @@ source ./docker-runner.sh
base=$(git merge-base "${1:-origin/main}" HEAD)
# Each hunk's added lines as path:first-last, in the working tree's numbering; a hunk that only deletes has none to mutate.
mutate=$(git diff --no-ext-diff --no-prefix -U0 --no-color "$base" -- 'src/*.ts' ':!src/*.test.ts' ':!src/conformance/property-harness.ts' | awk '
mutate=$(git diff --no-ext-diff --no-prefix -U0 --inter-hunk-context=0 --no-color "$base" -- 'src/*.ts' ':!src/*.test.ts' ':!src/conformance/property-harness.ts' | awk '
/^\+\+\+ / { path = $2 }
/^@@ / {
split($3, added, ",")
@@ -19,5 +19,5 @@ if [ -z "$mutate" ]; then
fi
leg "install ($node_image)" in_image "$node_image" sh -c 'npm ci --no-audit --no-fund && npm ci --no-audit --no-fund --prefix mutation-tests'
# A test file peaks near 2.6 GB: past four workers 6 GB kills some, and a killed worker's mutant reads as a RuntimeError, which fails the run.
# Four workers fit 6 GB in measured runs where fifteen had some killed, and a killed worker's mutant reads as a RuntimeError, which fails the run.
in_image_memory=6g leg "mutation tests ($node_image)" in_image "$node_image" sh -c 'mutation-tests/node_modules/.bin/stryker run mutation-tests/stryker.config.mjs --concurrency 4 --mutate "$1" && node mutation-tests/check-runtime-errors.mjs' sh "$mutate"
+1 -1
View File
@@ -6,6 +6,6 @@ export default {
tap: { testFiles: ['src/**/*.test.ts'] },
tempDirName: '/tmp/stryker',
testRunner: 'tap',
// TypeScript 7 has no JavaScript API for Stryker's tsconfig rewrite to call; a file that is not there skips it.
// Stryker skips its tsconfig rewrite, which calls a JavaScript API TypeScript 7 lacks, when this file is missing.
tsconfigFile: 'no-tsconfig.json',
}
+17 -10
View File
@@ -6,7 +6,7 @@
`Bar = 0.1`
`Next ID = 156`
`Next ID = 157`
## Items
@@ -25,6 +25,7 @@
| 73 | 0.3.0 | 33, 91, 109, 115, 132, 133, 145, 146, 150, 152 | | **Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions.** | 1 | 2 | 2 | 3 | 2 | 3 by 8 | 16.9 |
| 72 | 0.3.0 | 33, 91, 109, 115, 132, 133, 145, 146, 150, 152 | decision | **Re-create `gitea.larvit.se/larvit/adf-codec` as a read-only pull mirror of GitHub, its issues and Actions off and its description pointing at GitHub.** | 1 | 2 | 1 | 2 | 1 | 3 by 1 | 2.5 |
| 153 | 0.4.0 | | question | **Decide whether `src/markdown/` root may import `emit/`, `parse/` or `portable/`, and hold the answer in `.oxlintrc.json` and §The source parts by ADF and format.** | 1 | 2 | 2 | 3 | 2 | code health by 3 | 26.2 |
| 156 | 0.4.0 | | | **Stop a leg's container when its script is interrupted, so Ctrl-C ends `ci.sh` or `mutation-tests/run.sh` at once.** | 1 | 2 | 1 | 2 | 1 | code health by 2 | 20.9 |
| 128 | 0.4.0 | | | **Pin the portable flavour's block reading and writing with tests: callout titles past one line, a link beside other marks in a title, the nesting limit of callouts and task lists, refusals inside tasks and their paths, and empty or non-paragraph tasks.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 |
| 75 | 0.4.0 | | | **Make the generated-markdown property write block carries as `adf:` fences, canonical and hostile.** | 1 | 1 | 1 | 1 | 2 | code health by 2 | 17.4 |
| 154 | 0.4.0 | | | **Pair highlights over the inline reader's pieces by their offsets before building nodes, so no placeholder text node stands in for a delimiter.** | 2 | 1 | 2 | 3 | 4 | code health by 4 | 17.4 |
@@ -52,7 +53,7 @@
| 31 | 0.5.0 | | | **Make the branch-coverage figure repeat across runs of an unchanged tree.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 |
| 57 | 0.5.0 | | | **Make each `ci.sh` leg build what it reads, so one leg run alone tests the current tree.** | 2 | 1 | 1 | 2 | 3 | code health by 3 | 19.6 |
| 38 | 0.5.0 | | defect | **Spell a lone surrogate in a text node so it survives a UTF-8 encode.** | 1 | 1 | 2 | 2 | 2 | 1 by 2 | 17.4 |
| 76 | 0.5.0 | | | **State the files the package does not ship once, so the build, the lint ceiling and the coverage exclusions cannot drift apart.** | 1 | 1 | 1 | 1 | 2 | code health by 2 | 17.4 |
| 76 | 0.5.0 | | | **State the files the package does not ship once, so the build, the lint ceiling, the coverage exclusions and the mutation run cannot drift apart.** | 1 | 1 | 1 | 1 | 2 | code health by 2 | 17.4 |
| 56 | 0.5.0 | | | **Give each piece of `blocks.ts`'s block-walk state and `inline-content.ts`'s `Scan` one owner that returns what it changes.** | 3 | 1 | 2 | 4 | 5 | code health by 5 | 13.1 |
| 118 | 0.5.0 | | | **Spell a portable link's title through `oneLine`.** | 1 | 1 | 1 | 1 | 1 | code health by 1 | 10.5 |
| 82 | 0.5.0 | | | **Give the directive tests and fixtures random UUID v7 ids in place of `a-1`, `a`, `x` and `h`.** | 2 | 1 | 1 | 2 | 3 | code health by 1 | 6.5 |
@@ -198,6 +199,12 @@ a paragraph opening with a spellable `!adf:link` (§Nothing recurses unbounded).
`src/markdown/**` bans only `html/`; banning `emit/`, `parse/` and `portable/` for the root's own
files, with its `ci.sh` probe, extends the decision.
### 156. Stop a leg's container when its script is interrupted, so Ctrl-C ends `ci.sh` or `mutation-tests/run.sh` at once.
`in_image` runs `sh -c` as the container's process 1, which ignores the SIGINT `docker run`
forwards, so the container runs to its end: a `sleep 30` outlived Ctrl-C by 30 s. `--init` would
forward it. Found by the product-owner review of item 152, 2026-10-28.
### 128. Pin the portable flavour's block reading and writing with tests: callout titles past one line, a link beside other marks in a title, the nesting limit of callouts and task lists, refusals inside tasks and their paths, and empty or non-paragraph tasks.
Mutation testing left about 40 mutants alive in code moved verbatim into `src/markdown/portable/`
@@ -428,17 +435,17 @@ build leg left, so a leg run alone can pass on stale output.
`adfToLosslessMarkdown` emits it verbatim, so markdown stored as UTF-8 reads back U+FFFD; attribute
values already escape it.
### 76. State the files the package does not ship once, so the build, the lint ceiling and the coverage exclusions cannot drift apart.
### 76. State the files the package does not ship once, so the build, the lint ceiling, the coverage exclusions and the mutation run cannot drift apart.
Technical principle DRY: the set is written in `tsconfig.build.json`'s `exclude`, `.oxlintrc.json`'s
`ignorePatterns` and the `test` script's two `--test-coverage-exclude` flags, and §The size ratchet
assumes they agree. A helper added to one list lints test code under the shipped ceiling, or drops
shipped code from coverage, silently. Derive two from the third, or assert in a test that the three
agree. Found by the technical-principles audit, 2026-10-04.
shipped code from coverage, silently. Derive the others from one, or assert in a test that
they agree. Found by the technical-principles audit, 2026-10-04.
`mutation-tests/run.sh`'s pathspec and `mutation-tests/stryker.config.mjs`'s `testFiles` restate
which files are tests and test helpers, so a helper missing from them reads as survivors. Found by
the architecture review of item 152, 2026-10-28.
`mutation-tests/run.sh`'s pathspec restates the test files and test helpers, and
`mutation-tests/stryker.config.mjs`'s `testFiles` the test files, so a helper missing from the
pathspec has its mutants read as survivors. Found by the architecture review of item 152, 2026-10-28.
### 56. Give each piece of `blocks.ts`'s block-walk state and `inline-content.ts`'s `Scan` one owner that returns what it changes.
@@ -469,8 +476,8 @@ Found by the technical-principles audit of item 78, 2026-10-05.
### 58. Port `ci.sh`, `publish.sh`, `docker-runner.sh` and `mutation-tests/run.sh` to standalone Python scripts.
Technical principle "Prefer a standalone Python script over a shell script": `AGENTS.md` §3 teaches
bash footguns (`&&` chaining under `||`, `tee /dev/stderr`) the port removes. The port tests
`run.sh`'s turning of diff hunks into mutated line ranges, which a wrong range would pass silently.
bash footguns (`&&` chaining under `||`, `tee /dev/stderr`) the port removes. A wrong line range in
`run.sh` mutates the wrong lines without failing, so the port tests how it reads diff hunks.
### 34. Read emphasis flanking by the whole character beside an astral symbol.