fosmvvm-doctor and the complete review coverage register - #141
Merged
Conversation
…s rules The doctor: fourteen deterministic rules (R1-R14) over an AuditedProject read model — build settings, linkage and embedding, test plans, entitlements, deployment floors, the shared-module pair (ViewModels live in a shared module; it imports no server code). Three front doors: a CLI subcommand (swift run fosmvvm-bootstrap doctor), an SPM command plugin (swift package fosmvvm-doctor) that any package depending on FOSUtilities gets with zero installation, and --json on both for CI (Codable Finding/Severity report, contract tests). --shape moves the shape-dependent rules from unchecked into the audit. Design: docs/work/fosmvvm-doctor-design.md. The DocC CreatingAProject article gains § Diagnosing an existing project; README points existing projects at the doctor; CI gains a fast standalone lint job. The Xcode-only-projects checkout requirement is recorded in docs/deferrals.md.
…as a check The two-tier instrument completed. The coverage ledger (.claude/skills/fosmvvm-review/coverage-ledger.md) is the standing derivation: every enforceable statement in the truth layer mapped to the check or doctor rule enforcing it — completeness measured rule-by-rule, never by counting areas. Its register (G1-G26) is fully shipped: 86 checks across ten areas, including the datamodel area (junction-table principle), the multi-surface view area (SwiftUI, Leaf, React — LeafKit renders drift silently empty), the serverrequest-test area (the typed test door), the live-invalidation pairing, request naming per the dictionary, tests-never-touch-production, the behavioral-suite standing scope, existentials answering the principle's question, DocC discipline, shared-state serialization, and the one-top-level-App-State doctrine authored into architecture-patterns.md. The skill drives both tiers through one door: doctor runs before triage, structural errors halt area dispatch, one merged summary keeps the CI contract single. The full pipeline is qualified end-to-end against a scratch scaffold — halt path, nine-area dispatch, report contract — and every fold from those runs is in the check text, each clause carrying a named truth-layer ground. Generator skills learned their rules in the same stages; verification-target references live only in local planning files.
Taps a tagged view and proves the tap landed by the effect it causes, re-tapping once inside the dropped-first-event window a freshly launched app exhibits. The witness is any observable effect — a view appearing, the transported operations recording becoming readable — and the poll absorbs dispatch-and-transport observability only, never operation behavior: a stub operation records synchronously, so there is no work to wait out. Retires the hand-rolled tap-then-poll helpers consumers had to carry. Catalog entry included.
The first full fosmvvm-review run over a fresh scaffold found the walking skeleton drifting from doctrine ratified after it shipped; the templates now hold it. The card gains a CardFields form contract (protocol + localized en/es messages) adopted by both the wire body and the record; CardViewModel derives vmId from the record's identity threaded through the factory, and every screen ViewModel uses the type-keyed singleton form across all three shapes; the card gets its own CardView, registered for testing; the create request is renamed noun-first (CardCreateRequest); the server installs FOSMVVMVapor's ErrorMiddleware, module-qualified — without it, typed validation rejections flattened to bare 500s, caught by the scaffold's new tests; BoardServerTests drives both requests through the typed test door, including an invalid-body rejection proving the validator runs; stubs speak the reserved-fake vocabulary; the failed-boot shutdown error is logged; inert lint directives are removed; the scaffold ships docs/deferrals.md; the public Operations surface carries customer-frame DocC with call examples. Also ruled and applied: the test-host seam arrives with the App State — a skeleton whose only environment is mvvmEnv uses plain .testHost(), so the payload-free TestConfiguration and its dead overloads are gone from both shapes; and scaffolds ship no .VersionedTestJSON baselines by design — the user's own test runs mint their own. Verified by re-scaffold and a green swift test run.
… step 6
Release.version is what the scaffold's {{FOS_VERSION}} renders from,
so the pin bump happens automatically at the stamp. The ordering rule
that implies: template edits calling APIs first shipped in X.Y.Z land
only after the tag exists, because the skeleton matrix scaffolds and
builds against the network-resolved pin. Tag promptly after the stamp
for the same reason.
The ViewModel scan matched @viewmodel anywhere in any .swift file, so a comment mentioning the attribute — or a Package.swift manifest doing so — produced a false R13 finding (measured on the first field run: two comment mentions, one of them in the manifest itself). The match is now anchored to the start of a line, where a Swift attribute leads its declaration, and SPM manifests are skipped as build scripts rather than module sources. Two regression tests pin both shapes.
…eHeader
The emitter's expected file sets catch up with the template work this
branch shipped: the Fields pair, CardView, the renamed CardCreateRequest
and writer, the messages YAML, docs/deferrals.md, and the removed
test-host seam (both shapes). The full fast suite runs green locally —
the file-set tests were the one suite the template stages' scoped runs
never executed.
The standalone lint job excludes fileHeader from its --lint run: the
header template's {created.year} resolves from filesystem creation
dates, and a fresh CI checkout stamps every file with today's date, so
committed 2024/2025 headers fail on CI while passing locally. Header
enforcement stays local, where the dates are real.
The rule whitelisted Resources/ViewModels/ alone, so the Fields messages YAML the fields generator prescribes under Resources/FieldModels/ — and the scaffold now ships — read as a stray, failing the walking skeleton's doctor-clean assertion. The store's search is recursive, so both subtrees load; R8 now accepts both, with a regression test pinning the FieldModels sibling.
CardViewModel gained a required id parameter when vmId became identity-derived; the factory was updated but the correlation-seam unit test's three constructions were not — a target that compiles only under xcodebuild, which none of the SPM-side verification runs reach. Both app schemes (clientServer and localOnly) now compile build-for-testing locally, the gate that catches this class before CI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this delivers
Pre-0.14 projects — those generated before
fosmvvm-bootstrap— can now be audited against, and brought to, the bootstrap standard, through a two-tier instrument with one door.Tier 1 —
fosmvvm-doctorFourteen deterministic rules (R1–R14) over an
AuditedProjectread model: build settings, linkage and embedding, test plans, entitlements, deployment floors, and the shared-module pair (ViewModels live in a shared module; it imports no server code). Three front doors:swift run fosmvvm-bootstrap doctor, the SPM command pluginswift package fosmvvm-doctor(zero installation for any package depending on FOSUtilities), and--jsonon both for CI. Design:docs/work/fosmvvm-doctor-design.md.A first field run against a real pre-0.14 project produced 14 clean structural findings — and caught one doctor bug (R13 matched
@ViewModelin comments and manifests), fixed here with regression tests.Tier 2 — the
fosmvvm-reviewcoverage registerThe coverage ledger (
.claude/skills/fosmvvm-review/coverage-ledger.md) is the standing derivation: every enforceable truth-layer statement mapped to the check or doctor rule enforcing it, completeness measured rule-by-rule. Its register is fully shipped — 86 checks across ten areas — with each stage verified against drifted code where a target existed, every fold carrying a named truth-layer ground, and the generator skills taught their rules in the same stages. The skill runs doctor before triage; structural errors halt area dispatch; one merged summary keeps the CI contract single (jq '.summary.total.blocker == 0'). The full pipeline is qualified end-to-end (halt path, nine-area dispatch, report contract).The scaffolder, brought to its own standard
The first full review run over a fresh scaffold found the walking skeleton drifting from doctrine ratified after it shipped. The templates now hold it: a
CardFieldsform contract adopted by wire body and record, identity-derivedvmIdthreaded through the factory, a dedicatedCardView, noun-first request naming, the FOSErrorMiddlewareinstalled (typed rejections no longer flatten to 500s), typed-door server tests including an invalid-body drive, and the test-host seam reduced to arrive with the App State. Verified by re-scaffold and a green test run.FOSTestingUI
tap(provenBy:)— the witnessed tap: taps and proves the tap landed by its effect, re-tapping once inside the dropped-first-event window. Retires the hand-rolled tap-then-poll helpers consumers had to carry.Release process
docs/RELEASING.mdnow states that the scaffold's pin bump is automatic at theRelease.versionstamp, and adds step 6: template edits calling APIs first shipped in a release land only after its tag exists.Notes for review