Skip to content

backlog #1073: ASCQM 1.1 catalogue pass over all 74 live elements; close #1073, file #1089-#1093 - #269

Merged
wshallwshall merged 3 commits into
mainfrom
claude/ascqm-gap-hunt-findings
Aug 7, 2026
Merged

backlog #1073: ASCQM 1.1 catalogue pass over all 74 live elements; close #1073, file #1089-#1093#269
wshallwshall merged 3 commits into
mainfrom
claude/ascqm-gap-hunt-findings

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Runs BACKLOG #1073's ASCQM 1.1 weakness-catalogue pass over all 74 live elements with an
adversarial refutation stage. Closes #1073, files #1089-#1093, and records the ISO 5055 decline in
CLAUDE.md section 12.

Docs only: docs/BACKLOG.md + CLAUDE.md, +117/-1.

The decline is scoped, and the distinction is the point

ISO 5055 as a SCORE is declined -- three independently sufficient reasons: no free or open-source
5055-conformant Python analyser exists (the conformant ecosystem is C/C++/Java/C#/COBOL-weighted);
there is no contract counterparty for the clause the standard exists to serve (it is written into
development and outsourcing contracts, and this is OSS on PyPI); and a weakness-count score
collides with the anti-metric rule in docs/Code_Quality_Standards.md section 4.1.

The CATALOGUE was adopted -- it is free from OMG, and one bounded pass produced #1089-#1093.
Re-running the pass is legitimate; adopting the score is not.

#1092 corrects the project's own quality record

Eight verdicts flipped under measurement, and all eight flipped the same direction, covered ->
gap
-- which is a statement about systematic optimism in the original scoring, not scatter. Three
falsify a specific written sentence, including Code_Quality_Standards.md's "import/layer rules are
machine-checked in CI"
: the test walks ast.Import only and never opens a file under harness/.

This lands rather than waiting, because a published claim that a control is machine-checked when it
is not is precisely the compensating-control-on-a-false-premise defect the project's own prose rules
forbid. A correction toward accuracy should not be held because it is unflattering.

#1091 is written in the conditional, deliberately

It is a control that cannot see a class, NOT a live exposure. bandit is a Python AST scanner and
does not parse .ps1 or .yaml at all; gitleaks' generic rule is entropy-gated, so a low-entropy
credential falls below the threshold. The two defaulted credentials in the tracked tree are
development defaults.

Impact is stated as "a first deployment could carry a defaulted database credential into production
with both required gates green"
. Paraphrasing that as "credentials are exposed" would be the section
0 error, and the item says so in its own text.

Two disclosures carried in the items rather than left to review

  • The first workflow run silently judged 62 of 74 elements after one batch died, and returned a
    confident report with no sign a sixth was unread. Caught by arithmetic, re-run to full coverage.
    Both the omission and the fix are recorded in #1073.
  • #1093 flags two UNVERIFIED premises: CodeQL's real query coverage was inferred from suite
    selectors rather than executed, and every "not a required context" claim rests on the checked-in
    required-contexts.txt rather than the live API.

Coordinator note on that second premise -- resolved against the live API

security.yml:16 states "This repo is PUBLIC, so CodeQL runs free and IS a required context".
That is false. The live branch protection lists 13 contexts and CodeQL is not among them;
required-contexts.txt:109 documents the real reason (SARIF upload needs security-events: write,
which fork PRs cannot have). The checked-in file and the live API agree -- security.yml's comment
is the outlier. Being routed separately.

Gates

PASSED: ledger gate, forbidden-content leak guard, secret scan. backlog_status_check.py exit 0,
350 items each declaring exactly one status; five new headings, one banner each; zero prose glyphs.
SKIPPED (correctly, markdown): ruff / bandit / zizmor. NOT RUN: pytest, mypy -- no .venv in that
worktree; CI is the real check.

…55 decline in CLAUDE.md (closes #1073)

The BACKLOG #1073 pass ran over all 74 live ASCQM 1.1 elements with an adversarial
refutation stage on every non-not-applicable verdict. The measure stays declined; the
catalogue earned its keep on two narrow grounds and this commit records both.

FINDINGS FILED
  #1089  HL7 parse_path accepts component 0, so PID-5.0 reads AND OVERWRITES the last
         component. Reproduced by execution. The X12 twin validates and is tested; the
         HL7 side -- the default content type, the one carrying PHI -- has neither.
  #1090  write_reference_snapshot's json.dumps has no default hook; the FILE reference
         source does not coerce where its DATABASE sibling does. Every existing test
         uses CSV, so the suite cannot reach it.
  #1091  Credential detection reads neither .ps1 nor .yaml, and the entropy gate floors
         out on low-entropy secrets. Written in the conditional: this is a control that
         cannot see the class, NOT a live exposure.
  #1092  Eight verdicts flipped under measurement and ALL EIGHT flipped covered->gap.
         Three falsify a specific written claim, including the quality record's
         "import/layer rules are machine-checked in CI".
  #1093  Inventory of the rest, with the ~19 metric findings explicitly NOT to be filed
         (section 4.1: a count is not an item) and two unverified premises flagged.

THE DECLINE MARKER IS THE PART THAT OUTLIVES THE ITEM. CLAUDE.md section 12 now carries
it. A decline recorded only in a backlog item disappears when that item archives --
verified: #26 and #27 are both in BACKLOG-CLOSED.md today and survive as binding
decisions only because their markers were lifted into section 12.

COUNTS RESOLVED: the CISQ-vs-ASCQM conflict was a UNITS problem. CISQ counts CWEs
including children; ASCQM counts elements. Performance Efficiency = 15 is now confirmed
and its unverified mark is lifted; the "139 total" stays unconfirmed and that mark stays.

RECORDED AGAINST MYSELF: the first run silently judged 62 of 74 elements after one
triage batch died, and returned a confident report that gave no sign a sixth of the
catalogue was unread. Caught by arithmetic, not by the run. One of the missed elements
became a filed finding, so it was not harmless. It is this repo's own section 4.0
failure mode reproduced inside the tool built to hunt for it.

VERIFIED: backlog_status_check.py exit 0, 350 items each declaring one status; five new
headings, one banner each; zero prose glyphs in the new section.
NOT RUN: pytest, mypy -- no .venv in this worktree. Docs-only diff.
@wshallwshall
wshallwshall enabled auto-merge (squash) August 7, 2026 06:49
…e, which is where it rots

Caught by the b5-backlog-archival session. The marker exists precisely to outlive
#1073, and it cited `docs/BACKLOG.md #1073` -- but #1073 is closed, and closed items
LEAVE that file for docs/archive/backlog/BACKLOG-CLOSED.md.

The failure is invisible to every check: the markdown link to BACKLOG.md still
resolves, so nothing 404s. Only the human-readable "#1073" silently stops being
findable there. That is exactly how section 12's EXISTING #26/#27 pointers already
went stale -- verified against origin/main: neither heading is in docs/BACKLOG.md,
both are in the archive.

Now names both locations rather than guessing an archive anchor that may not match
the slug the archival pass generates. The repo's deep-link-to-archive convention
(44 occurrences in docs/BACKLOG.md) is the precedent.

NOT FIXED HERE, deliberately: the pre-existing #26/#27 staleness in the same list.
It is the same defect class but not this PR's scope, and the session that found it
is taking it.

I had noticed the #26/#27 staleness earlier in this session and judged it "not worth
chasing", then reproduced the identical defect in a marker whose whole purpose is
durability. Recording that, because the lesson is not "fix the pointer" -- it is that
a rot I declined to fix is one I had already stopped seeing.
Same tail-append collision as before, from the queue's documented serialization
point: #270 merged 357 lines of backlog filings (#1064-#1086), which invalidates
every other open backlog PR by construction. Not a defect in either branch.

RESOLVED BY KEEPING BOTH SIDES, and verified by INTENT rather than by absence of
conflict markers -- "no markers remain" cannot catch a dropped or duplicated item,
which is the failure a keep-both resolution actually invites.

The expectation was computed BEFORE the merge, so it could fail:

    parent HEAD       155 headings
    parent MERGE_HEAD 163 headings
    EXPECTED UNION    168      (155 + 13 only-on-main = 168; 163 + 5 only-on-HEAD = 168)

    merged            168
    LOST from HEAD    none
    LOST from main    none
    INVENTED          none
    DUPLICATED        none

The resolver REFUSES to write on any of those four conditions rather than reporting
them. Independent confirmation from the gate CI actually runs:
backlog_status_check.py --min-items 300 -> exit 0, 363 items each declaring exactly
one status, 168 in BACKLOG.md.

Only docs/BACKLOG.md conflicted. That was established with `git merge-tree
--write-tree --name-only`, which answers CONFLICTING; a changed-file list answers a
neighbouring question and inflated an estimate threefold earlier today. CLAUDE.md
was untouched by #270 and its archive-pointer fix is intact -- checked, not assumed.

Their side of the hunk was EMPTY (======= and >>>>>>> adjacent), so main's 13 new
items had auto-merged elsewhere. That is exactly the case where "keep our side" looks
correct and silently drops the other parent, which is why the check compares against
BOTH parents by heading rather than trusting the hunk.

git stdout decoded as UTF-8 explicitly: under cp1252 the banner glyphs raise
TypeError expected string got NoneType, which reads as a MISSING FILE rather than an
encoding fault.
@wshallwshall
wshallwshall merged commit f28359e into main Aug 7, 2026
32 checks passed
@wshallwshall
wshallwshall deleted the claude/ascqm-gap-hunt-findings branch August 7, 2026 16:03
wshallwshall added a commit that referenced this pull request Aug 7, 2026
Resolves the CLAUDE.md section 12 conflict predicted before #269 landed. #269
merged as f28359e while this PR was being opened.

KEPT BOTH SIDES, as the two changes are semantically independent:
  ours   -- the #26 / #27 / #222 pointers re-derived onto BACKLOG-CLOSED.md
  theirs -- #269's new ISO/IEC 5055 / ASCQM decline bullet

DROPPED, and this is the only deletion: main's stale
`([docs/BACKLOG.md](docs/BACKLOG.md) #27, ...)` line. It is the pre-fix text of
the very bullet this branch rewrites, carried in as context by #269's insertion
directly beneath it -- not content #269 authored. Keeping it would have restored
the rot.

Verified after resolution rather than assumed:
  - no conflict markers remain
  - all four spans present: #26, #27, #222 rewrites AND the ISO 5055 bullet
  - the stale #27 line is gone
  - every link target in the merged section 12 resolves (8 unique, all OK),
    with a known-bad path run through the same checker to prove it reports a miss
  - re-resolved every cited number against the post-merge tree: #26/#27/#222
    archived, #232 live, #1073 live-but-closed -- so #269's "once archived"
    wording is correct and its dual citation is satisfied

Merged rather than rebased so the PR's auto-merge arming survives.
wshallwshall added a commit that referenced this pull request Aug 7, 2026
…ed (BACKLOG #1073 R1/R2) (#271)

* docs(CLAUDE.md): re-derive every section 12 pointer; 3 of 12 had rotted

Section 12's decline markers exist so a decision stays binding after its backlog
item closes and archives. The mechanism works -- #26 and #27 survive only because
they were lifted here. Their own pointers were the ones that had decayed.

Scanned all 12 pointers in section 12 against origin/main (the primary checkout
runs behind and returns confident false negatives). Re-derived each target rather
than trusting the text.

ROTTED, now fixed -- all three named the live ledger for an archived item:
  #26  visual/template authoring -> docs/archive/backlog/BACKLOG-CLOSED.md
  #27  serial / ASTM             -> docs/archive/backlog/BACKLOG-CLOSED.md
  #222 typed action vocabulary   -> docs/archive/backlog/BACKLOG-CLOSED.md
       (#222 was a bare "BACKLOG #222" with no path, which reads as the live
       ledger; it is closed. Not named in the brief -- found by the sweep.)

LEFT AS-IS, verified to resolve:
  ADR 0037 / 0063 / 0039 paths     -- all three files exist
  ADR 0007 (bare, "see section 1") -- section 1 carries the path, file exists
  ADR 0076 Amendment D             -- exists, 0076-typed-action-...md:658
  BACKLOG #232                     -- genuinely still open in docs/BACKLOG.md
  docs/CONNECTIONS.md              -- still carries the serial decline, :2436
  parse_items, section 11, section 1 -- resolve

Added the ADR 0076 path inline, since Amendment D was cited by bare number only.

Verification: extracted every markdown link target in section 12 and resolved it
(7 unique, all OK), with a deliberately-broken path run through the same checker
to prove it can report a miss.

No gate added. A backlog number resolving to an archived item is not mechanically
distinguishable from one resolving to nothing without encoding the archive's
shape, and a gate that fails on a legitimate archive is one people delete.

NOT included: #1073's marker. It is not on origin/main -- it is in PR #269, still
open, and it already cites the archive correctly. Basing on an unmerged PR head is
the stacking trap, so this branch is cut from origin/main. PR #269 inserts a new
bullet immediately after the #27 bullet this commit edits; the two are
semantically independent but adjacent, so expect a textual conflict and keep both.

* docs: DECIDED -- Code_Quality_Standards.md section 4.1 gets NO back-pointer to #1073

R2 of the #1073 leftovers. The B5 brief left this "optionally" and nobody had
chosen. Deciding it NO, and recording the decision, because an unresolved
"optionally" is indistinguishable from a deliberate omission six months later --
which is exactly how #1073's own unpinned status came about.

Deliberately no file change. The decision is not to add an artifact, so an empty
commit is the whole record.

The case for was real: section 4.1 is the anti-metric rule the ISO 5055 decline
turns on, and a reader wondering whether 4.1 has ever been applied to a live
proposal gets no answer from 4.1 itself.

Rejected because:

1. R1, in this same branch, is the evidence. Three of section 12's twelve
   pointers had rotted, and the two rotted ones named in the brief were #26 and
   #27 -- the very entries cited as proof that lifting a decline into section 12
   makes it outlive its item. The decision survived; the trail back to it did
   not. This estate's demonstrated failure mode is pointers decaying, not
   decisions being unfindable.

2. It would be a fourth copy of the same pointer (the backlog item, the section
   12 marker, PR #269's prose, and 4.1), in a repo already bitten by the install
   procedure in three copies and the reference table in two.

3. It would be born rotted. #1073 is closed by PR #269 and archives on merge, so
   a clause written today naming docs/BACKLOG.md acquires the exact defect R1
   just cleaned up.

4. Section 4.1 is a four-sentence hard rule carrying no worked examples for any
   of the metrics it bans. A #1073 example would be the only one, which reads as
   though 5055 were the rule's primary case rather than one application of it.

Section 12 holds the binding decision, which is what that mechanism is for.
Reopening needs a reason that outweighs the maintenance cost, not just the
observation that the cross-reference is absent.
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