Skip to content

1.10.0: reorder-noise fold, ARXML/A2L consistency check, JSON/SARIF output - #33

Merged
longvo92 merged 9 commits into
mainfrom
dev/code-review-bugs-53eb16
Aug 16, 2026
Merged

1.10.0: reorder-noise fold, ARXML/A2L consistency check, JSON/SARIF output#33
longvo92 merged 9 commits into
mainfrom
dev/code-review-bugs-53eb16

Conversation

@longvo92

Copy link
Copy Markdown
Owner

Summary

  • Fold provably-safe statement reorders in generated C into noise (new reorder hunk kind) — Embedded Coder rescheduling independent assignments no longer reads as a change.
  • Cross-artifact consistency check: flag a model whose ARXML or A2L really changed but the generated C did not follow (a stale regenerate). Code-only changes are never flagged.
  • A2L changes are now named by object kind (+1 Characteristic / +1 Measurement) instead of a generic +1 A2L, in both the report and the viewer.
  • --json and --sarif output for pipelines to read the scan as data instead of screen-scraping the HTML report.
  • Drop unused gitsource.git_available().
  • One demo folder pair (tests/fixtures/demo) that exercises every feature above plus every noise rule in a single compare, with tests locking its claims.

Test plan

  • python -m unittest discover -s tests — 696 tests pass
  • python -m ruff check . — clean
  • python packaging/release_check.py 1.10.0 — ready
  • Rendered tests/fixtures/demo end-to-end (report, JSON, SARIF) and eyeballed the output

No production caller -- only a test's skipUnless used it, and the git
button gates on repo_root() being None instead. Inline the availability
check into the test so the helper does not linger as dead API.
Embedded Coder routinely re-emits the same independent assignments in a
different order (output ports, temporaries). The text reads it as a change,
but the block computes identical values -- the last residual codegen churn
the text-based rules cannot see past, because it is a reschedule, not a
rename, comment or whole-block move.

Decide it on meaning, not spelling: when the whole surviving change set is a
dependence-preserving permutation of a straight-line block of side-effect-free
scalar assignments, it is proven noise (kind 'reorder', ignorable). The scalar-
LHS + no-call restriction makes distinct names denote distinct objects, so
name-keyed read/write sets are the exact data dependence; two schedules that
agree on the order of every dependent pair are linear extensions of the same
DAG and compute the same result. Any unsafe line, multiset mismatch or flipped
dependent pair leaves every hunk real -- fail-safe, all or nothing.
A model's ARXML (its contract) and its generated C (its behaviour) come from
one regenerate and are expected to change together. When one is Modified and
the other Identical, each file is individually fine and the inconsistency lives
strictly between them -- the one failure a file-by-file view structurally
cannot point at, and the everyday sign of a partial or stale regenerate.

New consistency.py computes it from verdicts the tool already stands behind, so
it invents nothing. Surfaced in the report (a 'Consistency check' section) and
the terminal summary. Advisory ONLY: absence of a partner change can be
legitimate (a hand-written file, an ARXML-only edit), so it never folds a file,
moves a count or changes the exit code. A2L is not paired -- a recal touches no
code. Only the C<->ARXML pair, only when both are present in the compare.
The HTML report is for a human and the exit code is for a gate; neither lets a
build server read WHAT changed. New serialize.py writes the scan as data under
two shapes: --json is the whole record (per-file verdict, hunks, renames,
AUTOSAR extras, summary, consistency advisories) under a versioned schema, so a
consumer pins 'schema' and is insulated from an internal refactor; --sarif is a
SARIF 2.1.0 log of only the files needing action (modified/added/deleted/error),
for GitHub or Azure DevOps code scanning to annotate inline.

Both additive to the HTML report and independently usable. The JSON carries the
same exit_code the process returns (one _exit_code seam), so file and $? agree.
A failed machine-output write exits 2, same as a missing report -- a pipeline
that asked for the file must not proceed as if it got one.
…tures

fixtures/demo is a before/after pair a human runs to see the three new
features at once, and test_demo.py asserts each claim so the demo cannot drift:

- SpeedCtrl -- three independent gains re-emitted in a different order fold to
  Unimportant (reorder), proving the values are unchanged.
- TorqueLimiter -- C regenerated (gain 1.25 -> 1.45) while the ARXML stayed
  identical, so the consistency check flags it; nothing else does.
- PedalMap -- C and ARXML changed together (a new Scaled port) so no flag, and
  a new A2L characteristic is summarised without ever triggering one.

README.md gives the run command and what to look for; the SARIF omits the
Unimportant SpeedCtrl.c, so only the four actionable files are findings.
The direction was backwards. Flagging 'C changed but ARXML did not' fired on
the ordinary case -- an internal logic or gain edit touches no interface, so
the code legitimately moves alone. The real desync is the reverse: an ARXML
(interface) or A2L (calibration) change with the generated C left identical --
a new port or characteristic the code never picked up, the sign of a stale
regenerate.

Now flag a model only when a surface (ARXML or A2L) really changed while its C
did not; a code-only change is never flagged. A2L is included, and both
surfaces collapse into one message. Moved the report section below the AUTOSAR
changes and dropped the long caption. Demo gains a StaleGen model for the flag
and keeps TorqueLimiter as the code-only case that must stay quiet.
The AUTOSAR rollup showed a generic '+1 A2L', which hid whether a characteristic
or a measurement moved. Split it by kind (+1 Characteristic / +1 Measurement)
through one view_model seam so the report chips and the viewer header spell it
the same way. Ports, interfaces, runnables and events already carried their noun.

In the viewer the chips now ride on the file header line, right after the name
and before 'Change k of N', instead of a second 'AUTOSAR / A2L:' line below --
one line, no prefix, less vertical space spent restating the category.
One compare instead of three: fixtures/demo now also carries copies of the
noise-rule fixtures (rules/ -- comment, uuid, timestamp, rename, added,
deleted) and the model-grouping fixture (models/Ctrl) beside the four feature
models, so a reviewer sees every ignorable kind, an add/delete, and more than
one model in the Overview table in the SAME run that shows the reorder fold,
the consistency check and the A2L-by-kind chips.

Copies, not moves: tests/fixtures/{old,new,model_old,model_new} stay put
since other tests pin exact counts and paths against them; duplicating a few
small fixture files costs nothing next to that.

test_demo.py gains coverage for the folded-in paths (every ignorable kind
present, added/deleted present, the four models still their own Overview
rows) and the SARIF assertion moves from an exact set to inclusion checks now
that the merged tree has more actionable files than the four models alone.
@longvo92
longvo92 merged commit c1a4b8f into main Aug 16, 2026
6 checks passed
@longvo92
longvo92 deleted the dev/code-review-bugs-53eb16 branch August 23, 2026 04:40
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