Skip to content

Deeper verification gap: behavioral prose and examples unverified on Getting-Started, Examples, Architecture #3

Description

@cdub89

Three pages are verified only at the level of "this member exists". Their
behavioral prose has never been re-read against the FlexLib source, and their
examples have never been compiled. This is the largest remaining accuracy risk
in the repo.

Getting-Started.md, Examples.md, and Architecture.md each carry:

Every API member referenced on this page was checked against the 4.2.20
source: the member exists and is declared on the type used here. Prose
describing behavior and semantics has not been re-read against the source,
and the examples have not been compiled.

That status line is honest, which is why this is a tracked gap rather than a
bug. The concern is that member-existence checking is a much weaker guarantee
than it appears, and we now have two independent demonstrations of that.

Why member-existence verification is not enough

The 2026-08-02 adversarial review. A source-grep pass had already passed
these docs clean. Compiling them found three errors it had missed: a string
assigned to the AGCMode enum, s?.Mode on a type whose property is
DemodMode, and a float[] handler bound to a ushort[] delegate. Every
member involved existed. Every one was a compile break.

The 2026-08-02 Migration Guide sweep. Eight incorrect claims, and every
single member named on the page existed in 4.2.20. The errors were all in the
layer above existence: wrong delegate arity, a behavioral claim about a gain
curve that had not changed, and five "new in 4.2.x" attributions for things
already shipping in 4.1.5. A member-existence pass cannot catch any of these.
See 7983f65 and cdub89/SmartStreamer4#60.

Both cases share a shape: the member is real, and the sentence around it is
wrong. That is the class of error these three pages have never been checked
for, across roughly 3,600 lines and 48 C# blocks:

Page Lines csharp blocks
Getting-Started.md 1415 16
Examples.md 1313 7
Architecture.md 906 25

Blocking sub-task: a real regression from the Migration Guide fix

tools/Test-DocExamples.ps1 decides a block is a deliberate legacy sample by
looking for a v3-specific marker (Test-DocExamples.ps1:121-126):

$legacy = ($ctx -match '(before|old)\s*\(?v?3\.x') -or
          ($bodyTxt.ToLower() -match '//\s*(old|before)\s*\(?v?3')

The corrected fault-handler section introduced a block captioned **Old**:
that deliberately shows the 4.1.5 API (docs/Migration-Guide.md:48-57):

radio.HAAPI.AmplifierFault += OnAmplifierFault;

Neither pattern matches: the caption says **Old**: with no v3.x, and the
body has no // Old (v3 comment. So the block is classified as a fragment and
compiled against 4.2.20, where AmplifierFault does not exist. That is a
CS1061, which the script sorts as a real API error rather than
context-only noise.

This will fail on the first Windows-seat run and the failure is spurious. The
block is correct as written. The detection heuristic just predates the idea of
a deliberately-superseded 4.1.5 sample.

Options, roughly in order of preference:

  1. Generalize the heuristic to any superseded-API caption, not just v3.
  2. Add an explicit opt-out marker the script honors, which is more verbose per
    block but unambiguous.
  3. Leave it and accept a known-failing block, which defeats the point of a
    blocking gate.

Also stale: the inventory documented in CLAUDE.md and the comment at
Test-DocExamples.ps1:157 both say 135 blocks with 5 deliberate v3.x skips.
Cutting the 3.x before/after samples dropped this to 126 csharp blocks with
zero v3.x skips remaining. The script itself detects legacy blocks
dynamically so it still runs correctly, but both counts should be refreshed
from an actual -ListOnly run rather than edited by hand.

Suggested order of work

  1. Fix the legacy-detection regression above. It blocks everything else,
    because until it is resolved every gate run has a known false failure in it.
  2. Run .\tools\Test-DocExamples.ps1 on the Windows seat and fix what it
    finds. This is the strongest gate the repo has and it has never been run
    against these three pages. Cheapest large win available.
  3. Re-read behavioral prose against the source, one page at a time. Threading
    and lifecycle claims in Architecture.md are the highest risk, since they
    are the hardest for a reader to independently check and the least likely to
    surface as a compile error.
  4. Promote each status line only after both the compile gate and the prose
    re-read have actually happened for that page. Per CLAUDE.md, relabeling
    is not verification.

Worth considering for step 3: an independent Codex verification sweep per
page, since two model families agreeing on a reading of the source is
meaningfully stronger evidence than one. Verified this session that Codex can
read the vendor tree outside the repo root under --sandbox read-only.

Not in scope

The corrections table in API-Reference.md was spot-checked this session and
is sound. Eight rows (Slice.Mode, Slice.InUse, Meter.Value,
Panadapter.MinDBM/MaxDBM, Radio.RemoveSlice, RequestPanadapter,
Radio.MeterList) were re-checked against the 4.1.5.39794 tree to confirm they
are genuine documentation errors rather than API changes mislabeled as such.
None of the old names existed in 4.1.5 either, and the only MeterList hits
are private methods identical in both trees. No follow-up needed there beyond a
full sweep if someone wants one.

Activity

  1. cdub89 commented on Aug 2, 2026

    @cdub89
    OwnerAuthor

    The legacy-detection regression in the blocking sub-task is fixed in the working tree. Two corrections to what I wrote above, one of which lowers the severity.

    Correction: severity was overstated

    I said the block "will fail on the first Windows-seat run". That is too strong for the default invocation. The block classifies as a fragment (Set-BlockKind finds statements but no Main and no type declaration), and fragments are advisory unless -IncludeFragments is passed. So the accurate statement is: it surfaces as a real API error in the advisory section, and it gates only under -IncludeFragments. Still worth fixing before the first run, but it does not block the default gate.

    The fix

    Generalized the heuristic from v3-specific to any superseded-API sample, in three clauses:

    $legacy = ($ctx -match '(?m)^\s*\*\*(old|before)\b[^\n]{0,40}\*\*') -or
              ($ctx -match '(old|before)\s*\(?v?\d') -or
              ($bodyTxt.ToLower() -match '//\s*(old|before)\b')

    Clause 1 requires the bold marker. That is deliberate: docs/Getting-Started.md:29 reads "Before you begin, ensure you have:", which is caption-shaped and colon-terminated. A looser pattern matches it and would silently suppress any block within the 13-line lookback, which is the exact failure mode a gate must not have. Clause 2 covers unbolded headings and table captions with a version number. Clause 3 covers in-body markers and now matches any // Old / // Before rather than only // Old (v3.

    Verified against the real docs

    I cannot run PowerShell on the Linux seat, so I simulated both the old and new expressions over all 126 csharp blocks and diffed the classifications:

    File Line Before After Block
    Migration-Guide.md 51 compiled skip-legacy radio.HAAPI.AmplifierFault += ...
    Migration-Guide.md 85 compiled skip-legacy // Old (no longer compiles)

    Two blocks change, both correctly. Line 51 is the regression this issue was opened for. Line 85 is a pre-existing problem the old regex also missed: it references AmpIsSelected, which does not exist in 4.2.20, and its { ... } placeholders are not valid C# in any case.

    No other block changed classification, so there are no false positives across the rest of the corpus. The **New**: counterpart at Migration-Guide.md:61 still compiles, which is the behaviour we want.

    Still needs a real run on Windows to confirm, since a regex simulation is not the PowerShell engine and the script has never executed against this version of the docs.

    Also done

    Removed the hardcoded "54 of 135 blocks" from the comment at Test-DocExamples.ps1:157 and pointed it at -ListOnly instead of a number that goes stale on every edit. The equivalent stale inventory in CLAUDE.md is deliberately left alone: the honest numbers come from an actual -ListOnly run, which is Windows-only, so guessing them here would repeat the mistake this issue is about.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions