Repository navigation
Conversation
…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>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
There was a problem hiding this comment.
💡 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".
| elif inline and char == ")": | ||
| if depth == 0: | ||
| return rest[:index], rest[index:] |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
🟡 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.
| 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) |
| if _suffix(path) in LINK_SUFFIXES: | ||
| document.links = _links(lines) |
| if marker and marker.group(1)[0] == fence[0] and len(marker.group(1)) >= len(fence): | ||
| fence = None |
| if line[position] == "\\": | ||
| continue |




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
mainatc94878be(#96, T015), not the6827cafcthe 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 openxFactorymain)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.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 withvalidate.yml's install command; LANG=C.UTF-8; no GIT_* or XF_*).Red, before
families.pyexisted (commitfd5b0e51):Green at
3cdb445c:The corpus is T043's, copied into a fresh repository on
mainwithstandalone_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:INTENDEDdocument raises exactly one finding of its kind and class, the empty stub'sassistedand the accepted document'shuman-onlybroken-linkincluded; everyCLEANand entry document raises none; the corpus raises those seven and nothing else;near-duplicate.md(T043's pin); committed in two commits withcompost-bin-sizing.mdadded 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;locatorby the lines inserted and keeps its id (pinned, and as a working-copy edit);make_finding(..., pack_id="opendox", ...), carries only family fields (neverid,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;CATEGORIES,identity-collision,uncited-disappearance,ENGINE_KINDS);health/dispositions.yaml,health/packs.yaml,.opendox/governance.yamland a.jsondraw no finding, anddefault_adapter()lists none ofEXCLUDED_PATHS, pinned or not;summary, and a missingtitlewith no level-1 heading, raise nothing; an EMPTYtitle:with a#heading isderivable-front-matter;target#fragand `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;human-only;docs/README.MDandnotes/Index.mdare exempt; a self-link does not stop an orphan;candidates/(amanyword) andsources/(ashortword) locate their documents;open submissions/(alabel-only word),notes/candidate/(not top level), a top-level document, an out-of-setstage:and a missing one draw nothing;target_sha256, never a truncated string, and the locator dropstarget; an over-long other path becomesother_sha256;GIT_COMMITTER_DATEandGIT_AUTHOR_DATEin 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;.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 withtests/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-Iinterpreter loads none either;opendox/health/__init__.pyis a docstring and nothing else;orphanandnear-duplicateread 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_knowledgeruns with no binding, and the thresholdMeasured in a fresh interpreter (
python -I,env -i, an emptyOPENDOX_STATE_DIRandHOME, an audit hook refusing any socket or process event and recording every non-code file opened):So the family uses
embed(tokenize(...))'s cosine. Every pair of the 20 documents ofhealth-corpusandplain-documents(190 pairs):broken-link.md,garden/index.md)broken-link.md,garden/rain-barrel-checklist.md)The body has the wider margin, so the body is compared, and
NEAR_DUPLICATE_THRESHOLD = 0.875sits at its midpoint, 0.118 from each side. The constant's comment carries the table, andtest_the_threshold_sits_inside_the_measured_marginre-measures it on every run (NEAR_DUPLICATE_MEASURED = (0.9933, 0.7566)).For T046 and T052
FAMILIES = ("broken-link", "orphan", "near-duplicate", "derivable-front-matter", "stage-location-mismatch", "empty-stub", "stale-stub");CHECKSmaps each to its function, each runnable alone overread_corpus(adapter, corpus).families=Noneruns all; an unknown name raisesUnknownFamily(aValueError, with.family), which T052 maps toWorkbenchError.documents=Nonejudges every document; a collection of corpus-relative paths judges those, whileorphanandnear-duplicateread the whole corpus. A bare string is aTypeError.kind,path,identity,locatorwhere one helps,severity,resolution_class,message,evidence), sorted by path, kind and identity. T046 stamps them withmake_finding(**f, pack_id="opendox", pack_version=<installed>). Every finding iswarning, and itsevidencecarriesfamily_version: "1".CorpusRef.revisionis a run over that commit;Noneis a working-state run (tracked and untracked, not ignored). A refused corpus or a failed git query raises the adapter'sCorpusRefused, 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
data-model.md§ Families names no finding for a missingtitlewith no level-1 heading, or for a missingsummary, so neither raises anything, no kind is added, and the gap is recorded here.workbench.register_health_check(T046, T052), and no repair or proposal text (T053).README.mdandindex.mdare 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-duplicatecompares 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 owncheckis).local_git_adapteranddoxbench_intake.SETTINGS_DOCUMENTS(which the brief requires) bringdoxbench_bindinginto 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
3cdb445cagainstpostgres:16; the triple replaces this line before DRAFT-CLEAN.🤖 Generated with Claude Code