Repository navigation
Scaffold the app under the full quality leash, with structural ratchets - #21
Merged
Merged
Conversation
Wails v2 + React/TS scaffold, plus make verify as the CI-parity gate: pinned tools, 80% total / 85% patch coverage, golangci-lint with depguard layering and revive guardrails, gosec/govulncheck/semgrep, license allowlist, frontend complexity gates, and pin-drift tests that fail when a gate figure is stated two different ways. Closes #1
Wails defaults to webkit2gtk-4.0, which is EOL and not packaged on Ubuntu 24.04, so the Linux smoke build failed to link. DESIGN.md §9 names 4.1 as the Linux dependency; the webkit2_41 tag is what makes the build honour that. Set in the Makefile for local Linux builds and in the CI matrix so both sides use the same flag.
The analysis succeeded but the SARIF upload failed with 'Resource not accessible by integration': on a private repository that step calls the workflow-runs API, which needs actions: read. A job-level permissions block replaces the top-level read-all rather than adding to it, so the job was running without it.
Ten plain Go tests in the repo root that make architectural decay a build failure rather than a review opinion: package size, the pinned package list, exported surface, the App coordinator's field/method ceilings, dead-package detection, the pinned import graph, no-op-only interfaces, an integration-tag guard, the ESLint suppressions ratchet, and a guard that the gates themselves still run. Ceilings are pinned at measured actuals and only move down. Two exceptions are documented at the constant: LOC ceilings carry headroom (pinning a line count is a freeze, not a ratchet) and re-pin once #2/#5 land, and the coordinator's ceilings rise one composed handle at a time as services arrive. Each gate has a unit test on its own metric, because a detector that never fires and a working gate look identical from the outside. Closes #19
Add the structural ratchet gates
`git diff` cannot see untracked files, so a gate built on it skips every NEW file silently — and a silent skip is indistinguishable from a pass. `make lint` had this hole and reported green on ten unlinted files that CI then rejected. bindings-check had it too: a newly generated binding file is untracked, so the gate would report the bindings current while a whole module was missing from them. One shared guard (scripts/require-tracked.sh) now backs lint, bindings-check and patch-coverage, replacing the single copy that had been written for one gate and not its neighbors. A new structural gate fails the build when any Makefile target runs `git diff` without calling it first, so the class cannot be reintroduced. Also fixes the 11 lint issues CI reported (8 misspell, modernize, wrapcheck, gocritic) plus the British spellings CI had not reached yet.
Code scanning upload requires GitHub Advanced Security; on a private repository the analysis succeeds and the upload fails with 'Advanced Security must be enabled'. The analysis is what finds bugs, so it keeps running and scripts/codeql-gate.py still fails the build on any blocking alert — only the Security-tab UI is lost. Flip upload back to always when the repo goes public or GHAS is enabled.
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.
Closes #1. Closes #19 (merged in via #22).
The first line of Go in this repo is born under the full quality leash.
make verifyis the single CI-parity gate: every check it runs has an equivalent CI job at the same threshold.1. The app scaffold (#1)
Go module
github.com/txn2/m6t, Wails v2.13.0 with React + TypeScript + Vite. Single window, app idcom.txn2.m6t, placeholder UI.The UI reads the build identity across the bridge and says so when it is detached from the runtime — the placeholder proves the bridge, the embed and the ldflags stamp all work end to end.
The bound surface is one method. Wails exports every exported method of a bound object to TypeScript, so
Appkeeps exactly what the UI calls (Version()). An earlier draft exportedOptionsandContextand dragged the entire Wails options tree intomodels.ts.2. The leash (#1)
make verifyruns:tools-check fmt test coverage-report patch-coverage lint security semgrep licenses frontend-lint frontend-test bindings-check build-check dead-code.verify-releaseadds gremlins at 60% efficacy.verify-release)Tool versions are pinned (
golangci-lintv2.11.4,gosecv2.28.0,gremlinsv0.6.0,wailsv2.13.0) andtools-checkrefuses to run when a local version drifts from CI's.Drift-proofing:
pins_test.gofails the build when a gate figure is stated two different ways across the Makefile,ci.yml,codecov.ymlandCONTRIBUTING.md— including the cross-language complexity budgets and the claim thatverifyruns every gate CI runs.3. Structural ratchets (#19)
Ten plain Go tests in the repo root. The per-function linters all evaluate code inside one function; a god-package of a hundred tidy functions passes every one of them. These bound what those linters cannot see.
package_budget_test.gopackage_budget_test.gosurface_budget_test.goAppcoordinatorgodobject_budget_test.gomainpackage_graph_test.gopackage_graph_test.gonoop_interface_test.gointegration_guard_test.gofrontend_ratchet_test.gostructural_gates_test.goPinned actuals:
App1 field / 1 method ·internal/app67 LOC, 2 exported ·internal/buildinfo74 LOC, 2 exported · root 22 LOC, 0 exported · suppressions 0.4. CI fixes found by CI
Three failures surfaced on this PR that no macOS-local gate could catch. Each is fixed here, and two of them are now impossible to reintroduce.
Linux webview linkage. Wails defaults to
webkit2gtk-4.0, EOL and unpackaged on Ubuntu 24.04. Fixed with thewebkit2_41build tag, set in both the Makefile (uname -s) and the CI matrix so they cannot drift.CodeQL on a private repo. First failure was
Resource not accessible by integration— a job-levelpermissions:block replaces the top-levelread-all, so the job ran withoutactions: read. Fixing that exposed the real blocker:Advanced Security must be enabled. Code scanning upload needs GHAS, which private repos do not have. The analysis still runs andscripts/codeql-gate.pystill fails the build on any blocking alert; only the Security-tab UI is lost. Flipupload: neverback toalwayswhen this repo goes public or GHAS is enabled.The untracked-file blind spot — the important one.
git diffcannot see untracked files, so any gate built on it skips every NEW file silently, and a silent skip is indistinguishable from a pass.make linthad this hole and reported green on ten unlinted files that CI then rejected.bindings-checkhad it too: a newly generated binding file is untracked, so it would report the bindings current while a whole module was missing from them — live ammunition for #2.Fixed with one shared guard (
scripts/require-tracked.sh) behindlint,bindings-checkandpatch-coverage, replacing the single copy that had been written for one gate and not its neighbors.TestGitDiffGatesRequireTrackedFilesnow fails the build if any Makefile target runsgit diffwithout calling it first.Verified by exercise, not by assertion
Every gate below was run against a deliberate violation and reverted.
Leash:
coverage-reportfailsCOVERAGE_MIN80→81 in one placePATHtools-checkprints all 9 install commandsNot allowed license MPL-2.0--suppress-rulebaselines itbindings-checkreports `App.d.tsRatchets:
App2 fields, exceeding the ceiling of 1App2 methods, exceeding the ceiling of 1exports 3 identifiers (App, Options, Probe)internal/orphannot reachable from main+no entry in structuralPinsexceeding the ceiling of 0execute nowhere and rot silently269 LOC (ceiling 200)mainimporting buildinfoimports [...], pinned as [internal/app]excluded from the default test runGuards:
.gofilemake lintrefuses, names the filemake bindings-checkrefuses, namesApp.jsgit difftargetEach gate also has a unit test on its own metric — a detector that never fires and a working gate look identical from the outside.
A
git archiveof the tracked files builds, tests and packages the.app, so the scaffold stands up from a clean clone.Judgment calls worth challenging
ignore frontend/node_modulesin go.mod. npm packages ship Go source (flatted/golang) which./...pulled into the build — total coverage read 6.9% before this was caught.locCeilingNote, re-pin after PTY service #2/Project registry and tabs #5.App's 1/1 ceilings will rise as services land — one composed handle per PR, on that line, with the reason. What the gate stops is the accumulation nobody decided on.x/tools. Conservative direction, documented at the gate.verify— a database build takes minutes. It runs in CI and viamake codeql.Known follow-up
scorecard.ymlwill fail once this merges tomain:publish_results: truerequires a public repository. Not fixed here — it needs the same public/private decision as the CodeQL upload.Out of scope
Packaging (#16). Re-pinning the LOC ceilings against real service packages (#2, #5).