Skip to content

DRAFT: T044: the neutral health families, detection (plan 038, HA-2) - #101

Draft
brettheap wants to merge 27 commits into
mainfrom
r2/t044-health-families
Draft

brettheap wants to merge 27 commits into
mainfrom
r2/t044-health-families

Conversation

@brettheap

Copy link
Copy Markdown
Contributor

Lane: openxfactory-4 (openXfactory-4-openDox_extraction)

Arc: neutral-product-standalone-operability

T044 (plan 038, HA-2): the neutral families (detection).
Authority: Brett's word 6067802993, "Write now, stacked (Recommended)". This PR stays a DRAFT and lands after T027 (N-6 (a)) and after its bases.
Stacked on T041 (#97, f924db0) and T043 (#98, d6c9f29); it carries their commits until they land. Branched from main at c94878be (#96, T015), not the 6827cafc the brief first named (holder addendum 2026-10-11).
Rulings applied: #656 6069024023 (item 1) and 6069507373 (T044 items 1-9), with 6072086385 item 4 (no U+0000 reaches a finding).

The contract (plan 038 tasks.md, T044, at openxFactory main)

  • Realizes: 14.4 (part: detection), 6.2 (part: the check's body).
  • Falsifier: new tests/test_health_families.py, over T043's corpus, including the empty stub's class and an id that survives an edit above its finding.
  • Ruled: R2Q10, R2Q11, R2Q14; the holder's 6069507373 (T044 items 3 and 8). Decisions: OQ-H-8, -10, -11, -15, -16, -20, -21; N-13.

The falsifier, red then green

python -m pytest -q tests/test_health_families.py (venv built with validate.yml's install command; LANG=C.UTF-8; no GIT_* or XF_*).

Red, before families.py existed (commit fd5b0e51):

tests/test_health_families.py:36: in <module>
    from opendox.health import families as F
E   ModuleNotFoundError: No module named 'opendox.health'
ERROR tests/test_health_families.py
1 error in 1.10s

Green at 3cdb445c:

.....................................................................    [100%]
69 passed in 19.82s

The corpus is T043's, copied into a fresh repository on main with standalone_child.fresh_repository, and every expectation is imported from T043's module (PLANTED, INTENDED, CLEAN, ENTRY_DOCUMENTS, MOVED_LINK, ABSENT_LINK, NEAR_DUPLICATE_PAIR, NEAR_DUPLICATE_REPORTED, PLAIN), never re-typed. The nodes, each run over a pinned commit and over the working copy where it matters:

  • each INTENDED document raises exactly one finding of its kind and class, the empty stub's assisted and the accepted document's human-only broken-link included; every CLEAN and entry document raises none; the corpus raises those seven and nothing else;
  • the near-duplicate is on near-duplicate.md (T043's pin); committed in two commits with compost-bin-sizing.md added later, it moves there (ancestry before the tiebreak); unrelated adding commits (a merge of two branches) fall to the greater path; an uncommitted document is later than a committed one;
  • an edit above the broken link moves its locator by the lines inserted and keeps its id (pinned, and as a working-copy edit);
  • every finding is admitted whole by make_finding(..., pack_id="opendox", ...), carries only family fields (never id, pack_id, pack_version, baseline_class), has no number in its identity, no string over 200 characters and no forbidden key; no two findings share an id;
  • no family kind is an engine kind (CATEGORIES, identity-collision, uncited-disappearance, ENGINE_KINDS);
  • planted health/dispositions.yaml, health/packs.yaml, .opendox/governance.yaml and a .json draw no finding, and default_adapter() lists none of EXCLUDED_PATHS, pinned or not;
  • a header-less prose document is not an empty stub; a heading-only body is;
  • a missing summary, and a missing title with no level-1 heading, raise nothing; an EMPTY title: with a # heading is derivable-front-matter;
  • links inside ``` and ~~~ fences and inline code, external, scheme-relative, fragment-only and empty targets are not judged; target#frag and `target?query` resolve as `target`; a root-relative target, a folder, a percent-encoded name, and a link to an engine, settings or structured file are not broken; a footnote definition is no link; a reference definition and an image are links;
  • outside-corpus, ambiguous and absent targets are human-only;
  • docs/README.MD and notes/Index.md are exempt; a self-link does not stop an orphan;
  • candidates/ (a many word) and sources/ (a short word) locate their documents; open submissions/ (a label-only word), notes/candidate/ (not top level), a top-level document, an out-of-set stage: and a missing one draw nothing;
  • a broken target over 200 characters, and one holding U+0000, become target_sha256, never a truncated string, and the locator drops target; an over-long other path becomes other_sha256;
  • a stale stub (one-line and three-line bodies), its commit backdated through GIT_COMMITTER_DATE and GIT_AUTHOR_DATE in the test's own child environment, is flagged at 181 days and not at 179 or 180; a four-line body never; committer dates decide, author dates do not (both directions); a working-copy edit or an untracked stub is never stale;
  • pinned and working-copy readings agree on a clean tree;
  • .git/ and the working tree are byte-identical after a pinned and a working-copy run (a digest of every file, with a working-copy edit and an untracked file present);
  • families.py's import closure (lazy imports included, read with tests/import_scan.py's reader) holds no model or driver module, and its own imports name no model, binding, provider or bridge module; a fresh -I interpreter loads none either;
  • opendox/health/__init__.py is a docstring and nothing else;
  • each family runs alone; an unknown family is refused; a named document subset is judged while orphan and near-duplicate read the whole corpus; two links to one target are one finding.

Mutants

Pending: the run is in progress at 3cdb445c; the table replaces this line before DRAFT-CLEAN.

OQ-H-21: doxbench_knowledge runs with no binding, and the threshold

Measured in a fresh interpreter (python -I, env -i, an empty OPENDOX_STATE_DIR and HOME, an audit hook refusing any socket or process event and recording every non-code file opened):

OPENDOX_STATE_DIR = .../state.OYOl entries: []
bindings/model/provider/bridge loaded: []
opendox modules loaded: ['opendox', 'opendox.doxbench_knowledge', 'opendox.doxbench_memory_gateway']
files opened (non-code): []
socket/process events refused: []
dimension 96 norm 1.0 cosine 0.959043

So the family uses embed(tokenize(...))'s cosine. Every pair of the 20 documents of health-corpus and plain-documents (190 pairs):

compared planted pair highest other pair
body after the header 0.9933 0.7566 (broken-link.md, garden/index.md)
whole text 0.9962 0.8749 (broken-link.md, garden/rain-barrel-checklist.md)

The body has the wider margin, so the body is compared, and NEAR_DUPLICATE_THRESHOLD = 0.875 sits at its midpoint, 0.118 from each side. The constant's comment carries the table, and test_the_threshold_sits_inside_the_measured_margin re-measures it on every run (NEAR_DUPLICATE_MEASURED = (0.9933, 0.7566)).

For T046 and T052

from opendox.health.families import FAMILIES, default_adapter, run_families

adapter = default_adapter()   # WorkingTreeCorpus(write_path=None, excluded=EXCLUDED_PATHS)
corpus = adapter.resolve(CorpusRef(name=..., location=..., revision=<commit> or None))
found = run_families(adapter, corpus, *, families=None, documents=None)
  • FAMILIES = ("broken-link", "orphan", "near-duplicate", "derivable-front-matter", "stage-location-mismatch", "empty-stub", "stale-stub"); CHECKS maps each to its function, each runnable alone over read_corpus(adapter, corpus).
  • families=None runs all; an unknown name raises UnknownFamily (a ValueError, with .family), which T052 maps to WorkbenchError.
  • documents=None judges every document; a collection of corpus-relative paths judges those, while orphan and near-duplicate read the whole corpus. A bare string is a TypeError.
  • The result: a list of dicts holding each finding's family fields only (kind, path, identity, locator where one helps, severity, resolution_class, message, evidence), sorted by path, kind and identity. T046 stamps them with make_finding(**f, pack_id="opendox", pack_version=<installed>). Every finding is warning, and its evidence carries family_version: "1".
  • A pinned CorpusRef.revision is a run over that commit; None is a working-state run (tracked and untracked, not ignored). A refused corpus or a failed git query raises the adapter's CorpusRefused, so the run fails closed. The families print nothing.

Files changed

  • src/opendox/health/__init__.py (new): a docstring, no import.
  • src/opendox/health/families.py (new).
  • tests/test_health_families.py (new).

What is NOT done

  • Non-derivable front matter (ruling 2): data-model.md § Families names no finding for a missing title with no level-1 heading, or for a missing summary, so neither raises anything, no kind is added, and the gap is recorded here.
  • No engine, store, stamping, ids, baseline class, registration at workbench.register_health_check (T046, T052), and no repair or proposal text (T053).
  • Stated limits of detection, each a reading the brief leaves to this task, recorded in the module docstring: links are read per line; indented code blocks are read as text; setext headings count as body lines; only README.md and index.md are entry documents (ruling 4's names); a document whose path the finding contract refuses (a control character, a backslash, a drive-like first segment, invalid UTF-8) is never a finding's subject, as the projection leaves such a path out; near-duplicate compares every pair, quadratic in the corpus; whether a working-copy file differs from HEAD is read bytes against bytes through the adapter, so a file a filter or end-of-line rule rewrites reads as changed (conservative, as the adapter's own check is).
  • The import closure, for the record: local_git_adapter and doxbench_intake.SETTINGS_DOCUMENTS (which the brief requires) bring doxbench_binding into the closure; it holds records only. No model, provider, bridge or driver module is in it.

Full suite, as CI runs it

Pending: the full suite is running at 3cdb445c against postgres:16; the triple replaces this line before DRAFT-CLEAN.

🤖 Generated with Claude Code

brettheap and others added 27 commits October 8, 2026 16:34
…e copy-record moves (plan 038)

Work in progress, parked for an account swap. Not reviewed, not gated.
Mutant pass run 1: 52 killed, 1 survived (names rule checking the pack
only), 2 edits not applied; both get fixed next.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ttern escaped (plan 038)

A test of an id naming the right pack and the wrong kind kills the one
mutant run 1 left alive; the message pattern's U+2028 and U+2029 are written
as escapes, not as raw characters; the refused-identity cases get ids.
Mutant run 2: 57 of 57 killed. The full suite is still running.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t (plan 038, HA-3)

Twelve documents, ONE planted finding per kind and nothing else a neutral
family would flag: broken-link, derivable-front-matter (no title key, a
heading), stage-location-mismatch (in candidate/), near-duplicate, one empty
stub, human-only-finding (an orphan) and accepted-finding (a link to a file
that exists nowhere), plus a clean original, a control, two entry documents and
the moved link's target. Each planted document is named after its old literal
id, so batch Q's selection lines find it by path.

tests/test_health_corpus_fixture.py asserts the layout and the documents, the
inbound-link exemption (OQ-H-16) with the plain-documents measurement (8 files,
0 links), the near-duplicate tiebreak pin (near-duplicate.md, the greater
path), and that the corpus generates through the pinned validator over a fresh
one-commit repository; an empty title: is shown to be rejected by that same
check. T044 proves the findings themselves.

Lane: openxfactory-4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… order in the new test (SonarCloud python:S9073 x3, S3415)

Four findings at 860d0e7, all in tests/test_health_corpus_fixture.py; no behaviour moves (40 passed, and every mutant still killed).

Lane: openxfactory-4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the similarity ceiling to 0.1 (Copilot at adcaf8d)

Three findings in Copilot's review of adcaf8d, each a real gap with a simple payload:
- derivable-front-matter's heading may not be level 2 to 6 (a title derives from a level-1 heading);
- the plain-documents measurement read only top-level .md files, so a nested file left it green;
- the ceiling on every other pair of documents was 0.2 against a measured maximum of 0.0585; it is 0.1 (a pair at 0.103 now fails, one at 0.19 did not).

Lane: openxfactory-4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nce key is T046's (plan 038)

Copilot r4223399258 and Codex r4223401860 on openDox-code#97, both fix-now:
a locator line past Python's integer-string limit is refused as
finding-is-json, so to_json() never raises ValueError on a checked finding;
and the span refusal no longer formats its lines with :g, which raised
OverflowError on a 401-digit line. It quotes no value of the finding now.

Copilot r4223399173, fix-now in T041's scope: disappearance_identity() and
UNCITED_DISAPPEARANCE are removed. T041's task names the pathless and the
collision keys only; the re-raise of an uncited disappearance is the
baseline's (T046), and its pathless case is the holder's to rule (the PR
body's "For the holder", item 2).

Red first: the new locator cases fail on the previous head, 3 failed, one
with OverflowError. Mutants: 60 of 60 killed.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… 038)

health_contract.py: _walk split into _walk, _members and _scalar (cognitive
complexity 31, S3776); the pointers /identity, /locator and /resolution_class
named once each (S1192). No behaviour moves: 342 passed over the two test
files, and mutants 61 of 61 killed.

tests/test_health_contract.py: each pytest.raises block holds one call that
may raise (S5778, three); the two composite assertions split (S9073); the one
assertion that put the expected value first rewritten (S3415).

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… NIT)

The module docstring claimed the blank body meets data-model.md's criterion on any reading of it; it holds under leading_header's convention, and a reader that took --- fences for front matter would see the stub's header as body. Docstring only; 40 passed.

Lane: openxfactory-4
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…lan 038)

Item 1: the nine categories stand as drafted, and manifest-refused and
dispositions-refused are added; pathless_identity() admits both. What is the
contract module's to encode of the item's mappings: a category is its
finding's kind (ENGINE_KINDS, for T045's refusal of a pack declaring one);
one pack_id per category (ENTRY_CATEGORIES: against the entry's pack, the
rest against opendox); and engine_finding() builds the one finding per
category and entry, human-only, pathless, with one id across runs.

Item 2, option (D): disappearance_identity(original) returns a pathed
original's {disappeared_id} and a pathless original's {category: <its kind>,
entry: <its entry, or "">}. UNCITED_DISAPPEARANCE is back. Both forms are
tested, and so is the refusal of {disappeared_id} on an empty path.

Lane 3's REVIEW-W1 EARLY: the non-text field-name refusal is tested (its
mutant survived); the docstrings now say that where names admitted keys
verbatim and is unbounded, and a test pins it; the T045 hand-off cites
plan.md:458; lane 3's reversed 401-digit span is a test row.

Two test files: 379 passed. Mutants: 75 of 75 killed.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
T041 merges main before its gates, never rebasing (WRITER-RULES-R2). #90
touches no file of T041's.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… routes its reference check through finding_id() (plan 038)

The holder's 6069507373 (T046 item 2): the module-level finding_id() is the
single hash path. This test patches it; it is red at this commit, because
violations() still recomputes the hash with hashlib. The module change is
the next act.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… (plan 038)

The holder's 6069507373 (T046 item 2): the reference rule's hash check now
calls the module-level finding_id(), as make_finding() already did, so a test
that patches health_contract.finding_id patches every id the module sets or
checks. test_finding_id_is_the_one_hash_path, red at the previous commit, is
green; the mutants that restore a direct hashlib path are killed.

Lane 3's REVIEW-W1 MINOR at 8e2124e, bounded as the holder preferred: a
violation's where is at most STRING_MAX characters, the place's own pointer
or its nearest ancestor's that fits, and a pointer that stops stays stopped,
so it never names a path that is not there. Fifteen nested 200-character
keys of "/" made a 6026-character pointer; now it is /identity. The
docstrings say so.

Two test files: 389 passed. Red first: 6 failed against the previous module.
Mutants: 80 of 80 killed.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uling cited; SonarCloud's pre-check (plan 038)

The holder's openxFactory#656 6072086385 item 4 (the NUL seam, fix-now):
Postgres jsonb cannot store U+0000 (SQLSTATE 22P05), so no string a
finding carries holds it, keys and values alike. The schema admits it in
identity, evidence and locator.target, so the engine's new rule
text-holds-no-nul (ENGINE_RULES, now five) refuses it there, as a
FindingRefused with a bounded where; in message, path and pack_version
the schema's own control-character rules refuse it already. For a pack's
output the refusal is T045's whole-output pack-output-refused
(6069024023 item 1's mapping); T042's _json_text refuses it too.
locator.target's check moves into _target(), which keeps _locator's
cognitive complexity at 12.

6072086385 item 1: ENTRY_CATEGORIES is confirmed as written; its comment,
the module docstring and engine_finding() cite it beside 6069024023.

SonarCloud, checked before the push: "/identity/entry" is named once
(_AT_ENTRY, S1192), and the one expected-first assertion SonarCloud's
S3415 flow named at 8e4065b now puts the module's constant first.

Tests: 409 passed over the two files; 19 of the new cases fail against
f9cc4b0's module. Mutants: 85 of 85 killed, five of them new.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…W-W1 items at f9cc4b0 (plan 038)

The holder's openxFactory#656 6072197564, on lane 3's NAMES points:
- (b) a pathless finding's identity.category is one of a CLOSED set,
  PATHLESS_CATEGORIES: the engine's categories and identity-collision.
- (d) ENGINE_FIELDS is split by behaviour: IGNORED_FIELDS (a pack's id is
  ignored) and STAMPED_FIELDS (pack_id, pack_version and baseline_class
  are the engine's). No behaviour moves.
- (e) INSTALL_CATEGORIES (no-sandbox, manifest-refused,
  dispositions-refused) take entry "": a run raises ONE install-level
  finding (data-model.md:382), so a non-empty entry is refused by
  pathless_identity(), engine_finding() and check_finding() alike. This
  is also lane 3's MINOR at health_contract.py:865.

Lane 3's REVIEW-W1 at f9cc4b0: three rows for the list-index branch of
the where bound (201 and 207 characters, and a stopped pointer that must
not resume to /identity/0/a); a pathless original whose kind is not its
category, whose disappearance takes the original's kind (and, under (b),
admits no re-raise of its own).

Tests: 433 passed over the two files; 14 of the new cases fail against
0e24062's module. Mutants: 93 of 93 killed, eight of them new.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…MINOR at c620dac, as the holder ruled it) (plan 038)

check_finding() refused a non-empty entry only for INSTALL_CATEGORIES, so
it admitted {identity-collision, <an entry>} and {pack-crashed, ""}, two
forms the engine never builds. The holder's ruling, refining 6072197564
(e): a category in ENTRY_CATEGORIES names its pack's entry, never "";
INSTALL_CATEGORIES and identity-collision take entry ""; entry-refused
takes either. One helper, _entry_breaks_form(), holds the rule for
check_finding() and pathless_identity() alike.

Tests: 459 passed over the two files; 10 of the new cases fail against
c620dac's module.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…id ruling (Copilot r4226093840 on openDox-code#97) (plan 038)

Docstrings only: the overview of tests/test_health_contract.py said four
engine rules after text-holds-no-nul made five, and two docstrings still
said "one pack_id per category", the phrase 6072086385 item 1 replaced.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… 038)

Docstring only: the entry-form rule is the holder's openxFactory#656
6073087924, on lane 3's MINOR at c620dac, so check_finding() admits
exactly what engine_finding() builds.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nd; refused_entry(); n6 and e3 (plan 038)

The holder's openxFactory#656 6082100803: for ENTRY_CATEGORIES,
check_finding() refuses an entry that is empty, the reserved opendox, or
longer than NAME_MAX, so it admits exactly what engine_finding() builds.
Lane 3's exactness probe (every category against eleven entries) found 21
mismatches at 4cc065a and finds 0 here; test_check_finding_admits_
exactly_what_engine_finding_builds holds it.

6086098003 item 1: REFUSED_PATCH joins ENGINE_KINDS, a PATHED engine
kind, in neither CATEGORIES nor PATHLESS_CATEGORIES. Item 3 (b): a
U+0000 row for path. Item 4 and 6088484643: refused_entry() builds
entry-refused's identity.entry: "" for no id, the id as written when it
is [a-z0-9-]+ of at most 200 characters, and otherwise sha256- and the
SHA-256 of its canonical text (json.dumps with sorted keys, no
whitespace, ASCII escapes, allow_nan, default=str; repr() when that
raises). It never raises.

Lane 3's surviving mutants at 4cc065a were equivalent ones on dead
guards, so the guards go: n6, the bool guard before _writable() in
_locator (a bool is always writable, and _line() refuses it next); e3,
engine_finding()'s own entry check, which pathless_identity() already
made dead.

Tests: 502 passed over the two files; 35 of the new cases fail against
4cc065a's module.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… (plan 038)

Python 3.12's json.dumps and repr() both reach a 3000-level value, so the
test of the fallback text now nests 50,000 levels, past the C recursion
limit both share; the mutant that stops catching RecursionError there is
killed.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… (b)) (plan 038)

The holder's ruling on Copilot thread 4234200849 (openxFactory#1283): the
canonical text's fallback is ascii(id), repr() with every non-ASCII
character escaped, so the text is always ASCII and is encoded strictly.
The digests do not move: the previous fallback, repr() encoded with
backslashreplace, spelled every value the same way, so the new row for a
non-ASCII key in a mixed-type mapping passes against 4ffc411's module too.
The mutant that puts repr() back is killed.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…w (plan 038)

Module only, not for #97 yet: the ascii() fallback also catches ValueError
(an integer past the 4300-digit limit) and takes ONE fixed text, <past the
int-digit or recursion limit>; the default hook spells a set or frozenset
as its members sorted by ascii() text. The item 8 test rows and mutants
are next.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Lane 3's MAJOR and MINOR at 471b723, as the holder ruled them:
- (a) the four ids lane 3 reproduced, integers YAML yields past Python's
  4300-digit limit (a long 0x literal, a long 0b literal, one in a list,
  one in a mixed-key mapping), each a sha256- entry of the one fixed text
  and never a ValueError; the 50,000-level value takes the same text.
- (b) a YAML !!set id in _REFUSED_IDS, and one set id digested in four
  interpreters under four PYTHONHASHSEED values: one entry, while its
  str() is not one spelling there, so the row bites.

All 7 new cases fail against 471b723's module. 509 passed over the two
files.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tests/test_health_families.py over T043's corpus, before
src/opendox/health/families.py exists.

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e; 42 of the falsifier's nodes green before the park

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he front-matter case scoped to its family)

Lane: openxfactory-4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@brettheap
brettheap requested a balanced review from Copilot October 11, 2026 17:12
@brettheap

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-11T17:17:34.485072Z 3cdb445 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@sonarqubecloud

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3cdb445ca0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +538 to +540
elif inline and char == ")":
if depth == 0:
return rest[:index], rest[index:]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor escaped parentheses in Markdown link destinations

When an inline destination contains a valid backslash-escaped parenthesis, this branch treats the escaped ) as the link terminator. For example, [valid](docs/a\)b.md) is parsed as targeting docs/a\, so broken_links() reports a false finding even when docs/a)b.md exists. Skip escaped punctuation while balancing the destination and resolve the unescaped target.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Link parsing has correctness gaps and corpus processing lacks resource bounds.

4 open findings
What changed in this PR

Adds the neutral health-finding contract, representative corpus, and seven document-health detection families.

Changes:

  • Introduces health finding schemas and contract validation.
  • Adds the health corpus and comprehensive detection tests.
  • Implements link, orphan, duplicate, metadata, location, and stub checks.
File Description
src/​opendox/​health/​families.py Implements seven health families.
src/​opendox/​health/​__init__.py Adds the lightweight health package.
src/​opendox/​health_contract.py Defines the neutral finding contract.
src/​opendox/​contracts/​__init__.py Registers the finding schema copy.
src/​opendox/​contracts/​copies.yaml Pins the fifth packaged contract.
src/​opendox/​contracts/​schemas/​opendox-health-finding.schema.yaml Adds the finding schema.
tests/​test_validator_input_set.py Verifies the expanded contract set.
tests/​test_health_families.py Tests health-family behavior.
tests/​test_health_corpus_fixture.py Validates the health corpus.
tests/​fixtures/​health-corpus/​README.md Documents and links the corpus.
tests/​fixtures/​health-corpus/​accepted-finding.md Plants an accepted broken link.
tests/​fixtures/​health-corpus/​broken-link.md Plants a movable broken link.
tests/​fixtures/​health-corpus/​compost-bin-sizing.md Provides the duplicate original.
tests/​fixtures/​health-corpus/​derivable-front-matter.md Plants derivable metadata.
tests/​fixtures/​health-corpus/​empty-stub.md Plants an empty stub.
tests/​fixtures/​health-corpus/​human-only-finding.md Plants an orphan.
tests/​fixtures/​health-corpus/​near-duplicate.md Plants a near duplicate.
tests/​fixtures/​health-corpus/​candidate/​path-edging-options.md Provides a matching-stage control.
tests/​fixtures/​health-corpus/​candidate/​stage-location-mismatch.md Plants a stage mismatch.
tests/​fixtures/​health-corpus/​garden/​index.md Provides an exempt index.
tests/​fixtures/​health-corpus/​garden/​rain-barrel-checklist.md Provides the moved link target.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +287 to +295
for identity in listed:
if identity.key in EXCLUDED_PATHS or _suffix(identity.key) not in JUDGED_SUFFIXES:
continue
classification = adapter.classify(corpus, identity)
if classification.kind is None:
continue # not a document (the projection's rule)
raw = adapter.read(corpus, identity).content
self.documents[identity.key] = _read_document(
identity.key, raw, classification.missing_fields)
Comment on lines +461 to +462
if _suffix(path) in LINK_SUFFIXES:
document.links = _links(lines)
Comment on lines +474 to +475
if marker and marker.group(1)[0] == fence[0] and len(marker.group(1)) >= len(fence):
fence = None
Comment on lines +557 to +558
if line[position] == "\\":
continue

This branch has not been deployed

No deployments
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.

2 participants