Skip to content

📝 docs(audit): pre-tag remediation — dead URLs, ADR truth, and the recorded deferrals - #42

Merged
konih merged 7 commits into
mainfrom
lane/audit-pretag-docs
Aug 9, 2026
Merged

📝 docs(audit): pre-tag remediation — dead URLs, ADR truth, and the recorded deferrals#42
konih merged 7 commits into
mainfrom
lane/audit-pretag-docs

Conversation

@konih

@konih konih commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Remediation lane for the pre-tag items of the 2026-08-09 project audit. Text and records
only, with two deliberate exceptions noted below. Rebased onto main after #41 merged.

Every claim landed here was executed, not reasoned — the audit's root finding is that claims
in this repo get written from another agent's prose.

Group 1 — the dead-URL family (DOC-02, P1)

The repo is named Assent. GitHub repo URLs are case-insensitive; Pages paths are not.

curl -sI https://platformrelay.github.io/assent/  -> HTTP/2 404
curl -sI https://platformrelay.github.io/Assent/  -> HTTP/2 200

Fixed in cmd/assent/main.go (the URL the released binary prints), the five README links,
docs/usage/cli.md, mkdocs.yml's site_url (which drives every canonical link and all 63
sitemap.xml <loc> entries — all of them currently dead), D-044, the E9 spec, and
internal/catalogue's DocsBase. Swept, not worked from a list; CHANGELOG.md and commit
messages contain zero occurrences, so the gate is safe repo-wide.

cli.md:58 sits in the byte-pinned help block: TestCLIDocCoversSubcommands was observed
red with only main.go changed, then green with both halves.

New gate in hack/docs/truthlag_pins_test.sh (already in task check): every
platformrelay.github.io occurrence repo-wide, .go included, must carry site_url's prefix.
Four proofs: a lowercase flip reds naming the file; mutating site_url reds 11; a missing
site_url reds rather than passing; a needle matching nothing reds as vacuous.

It is a prefix check, not a liveness check, and the comment says so and names the known
dead path — a gate that greenlights a URL we know 404s is the pattern the audit indicts.

Group 2 — the dead rule-docs URL (DOC-03, P1)

/Assent/rules and /Assent/rules/ both 404 against a 63-page sitemap. Casing cannot fix it.
The run path no longer mints; it carries the rule's authored docs.url, and
renderDocsSection already omits the line when empty.

Nothing red'd when the minting was removed — a test that could not fail — so both polarities
are now pinned and mutation-proven against the restored minting. Render goldens are
unaffected (none contained the URL); internal/render and examples/render pass.

Honest limitation: the fallback is dormant by schema, not merely unused — the frozen
merge-policy schema is additionalProperties: false over eight keys, so an authored rule-level
docs: is rejected at load (ARCH-08). Present-day behaviour is "no documentation link", which
is the point. assent catalogue's JSON still carries DocsURL (D-017 B10 field set — an
openspec change); the constant documents the dead space rather than implying it resolves.

Group 3 — ADR truth

ADR-0013 Amendment 1's Rego pointer is dropped: zero opa/rego deps, no rego property in
any frozen schema. The same false pointer existed in production Go (evaluate.go) and is
corrected with it — a copy the finding did not name. ADR-0002 and ADR-0006 annotated (CI's only
e2e touch is go vet -tags e2e, which runs nothing). ADR-0009's index row corrected — and
0002/0006/0019's too, since leaving them plain would reproduce D-135's own error.

Judgment call — ADR-0019's unmet MUST: annotated, not emitted. It is one instance of
ARCH-11 (doctor prints essentially none of its typed report), so emitting one field would
half-close it and leave the report inconsistent with itself; and it is a user-visible CLI
output change, which does not belong in a docs lane before a tag. Recorded in D-138 and queued
for the v0.2.1 ARCH-11 slice.

Group 4 — decision-log truth

D-134's "Corrected surfaces" carried phase: observe advice the same row retracts ~2,000 words
later as ARM-08; the retraction now sits at the natural stopping point. D-041 gets a supersede
pointer, content byte-unchanged. vision.md corrected — measured here:
assent run --dry-run -> flag provided but not defined: -dry-run, exit 2. The commit that
introduced that claim was itself a docs-truth fix that promoted dry-run into the shipped half.

Group 5 — recorded deferrals

D-138 (RELI-01/02/03) and D-139 (SEC-01/04/05) — two rows, not one, because a single
3,000-word cell would reproduce Group 4.1's exact defect. OQ-31 records the GUARD-1
communication question, undecided. OQ-29 raised to P1: its escalation condition was already
true — MkDocs publishes every file in docs_dir regardless of nav;
architecture/policy-profiles/ returns 200, the sitemap has 63 entries against ~10 nav
entries, and the false invariant is in search_index.json (420 sections indexed).

Also internal/forge/forge.go's RELI-03 comment, corrected in place: it cited
reset_approvals_on_push (zero Go files) and deferred to P4-E1-S10, a slice that shipped.

cli.md gains the --checkout known-limitation section required by the security lens —
framed as how the checkout is constructed, claiming no mitigation the tool performs.

Deliberate exceptions to "no behaviour change"

  1. Group 2 changes what the run path renders — intended, tested, mutation-proven.
  2. D-044's URL edited in place rather than superseded: a dead link inside a record is a
    factual defect, not a decision to reverse.

Judgment call for the operator: rename the repo?

Renaming Assent -> assent would fix this at the source and is the better permanent answer —
everything else already spells it lowercase (module path, repo_url, site_name).

I do not think this PR is a workaround pending that. It is correct today, and it makes the
rename cheaper: with the gate in place a rename becomes a one-line site_url change plus a
mechanical sweep the gate itself verifies. Note the operator's homepageUrl is already
/Assent/, so the live config agrees with the capital-A world, and a rename inverts every
reference here — it is not a drop-in.

Gates

task checkall 14 stage banners, EXIT=0, coverage 90.4%, clean tree, with
golangci-lint cache clean and isolated GOCACHE/GOLANGCI_LINT_CACHE:

fmt · vet · lint · test · coverage · build · dogfood-comparison · compare-exitgate-test · changelog-verify · release-changelog-gate-test · release-verify-tag-gate-test · docs-gates · lint-depguard-test · lint-workflow-pins-test

An intermediate run reported EXIT=201 at changelog-verify (the changelog-last step), so
the exit code was read from the log, not inferred.

Rebased with rerere disabled; verified by set difference and row content that no decision
row was dropped — D-136/D-137 are byte-identical to main, and the only rows that differ are
D-041, D-044 and D-134.

Do not merge without review.

Found but deliberately NOT fixed here

Four decision rows contain unescaped | inside inline code, so they render with phantom
columns on the published site
(decisions/decisions/ is in the nav):

Row Offender
D-055 5 cells, expected 3
D-056 9 cells, expected 3
D-135 8 cells, expected 3
D-137 4 cells — `` `:memo:

D-135 is the one that matters. It renders as 8 cells, and D-135 is both the row
ADR-0009's Status line sends readers to and a row whose entire subject is a docs-truth
correction. So the correction about a false claim is itself mangled on the published page —
a further instance of this audit's root finding, not a formatting nitpick.

Pre-existing, not raised by the audit, found by a column-count scan while checking my own rows
(mine are correct: D-138/D-139 = 3 cells, OQ-31 = 4).

Sweep boundary, stated: the scan covered docs/decisions/decisions.md and
docs/planning/open-questions.md only. It did not cover docs/adr/README.md or the ADR
Status rows, which are also tables and which this PR edits — those edits add no pipes, but they
are unscanned.

Not fixed in this lane on purpose: it edits four decision rows including two very recent ones,
which invites rebase conflicts with other lanes, and the durable answer is a gate rather than a
one-off escape. Suggested follow-up: escape the pipes and add a ~6-line column-count pin to
hack/docs/truthlag_pins_test.sh, the same cheapest-gate shape as the DOC-02 pin in this PR.

konih added 7 commits August 9, 2026 04:55
…th (DOC-02)

The repo is named `Assent`. GitHub repo URLs are case-insensitive; GitHub Pages
paths are not — so every in-tree `platformrelay.github.io/assent/...` reference
404s. Measured live: `/assent/` -> 404, `/Assent/` -> 200.

Corrected in `cmd/assent/main.go` (the URL the released `assent --help` prints),
the five README links, `docs/usage/cli.md` (byte-pinned against the help text, so
both halves move together), `mkdocs.yml`'s `site_url` — which drives every page's
canonical link and all 63 `<loc>` entries in `sitemap.xml` — plus D-044 and the
E9 spec. `internal/catalogue`'s DocsBase casing goes with them.

New pin in `hack/docs/truthlag_pins_test.sh` (already wired into `task check`):
every `platformrelay.github.io` occurrence repo-wide, `.go` files included, must
carry `mkdocs.yml`'s `site_url` prefix. It is a prefix check, not a liveness
check; the comment says so and names the known dead path.

D-044's URL is corrected in place rather than superseded: a dead link inside a
record is a factual defect, not a decision to reverse.
…read (DOC-03)

`run_render.go` attached `catalogue.DocsBase + "/" + pack + "/" + rule` to every
rule on the run path, rendered as a `📖 [Full documentation](…)` link in the
contributor's thread. No `rules/` space exists on the docs site — measured,
`<site>/rules` and `<site>/rules/` both 404 against a 63-page sitemap — so the
one affordance a blocked contributor clicks was dead on every finding. Casing
does not fix it; the URL space does not exist in either case.

The run path now carries only the rule's authored `docs.url`, and
`renderDocsSection` already omits the line when that is empty: no link beats a
broken one. Today the fallback is dormant BY SCHEMA, not merely unused — the
frozen v1alpha1 merge-policy schema is `additionalProperties: false` over eight
keys, so an authored rule-level `docs:` is rejected at load (audit ARCH-08).

Both polarities pinned, since "no link" is also what deleting the feature would
produce: absent -> no link and no docs-site URL anywhere in the body; authored ->
that URL verbatim. Mutation-proven — restoring the minting reds both subtests.

Building the `/rules/` pipeline stays out of scope. `assent catalogue`'s JSON
still carries DocsURL (D-017 B10 field set, an openspec-level change); the
constant now documents the dead space instead of implying it resolves.
…mit (SEC-01)

This release hardens `--checkout` extensively (D-133 refuses any symlink anywhere)
and the page already names "run without `--checkout`" as the first remedy — so it
reads as though the flag has been made sound. It has not.

Measured, not transcribed: `cmd/assent/checkout.go` contains zero occurrences of
`SHA`/`Sha`, `run.go` has no step comparing the checkout to `pins.sourceSha`, and
the pins and the compare-and-swap merge come from `info.SourceSHA` — the forge's
view. So assent judges the tree it is handed and the forge merges the commit it
knows about, with nothing relating the two.

Stated as a property of how the checkout is CONSTRUCTED, which is what it is: an
operator who builds `head/` from the merge-request head SHA and cancels
superseded pipelines is unaffected. Deliberately claims no mitigation on assent's
part — it probes no such project setting, and citing one it never reads is the
pattern the audit found three times.
ADR-0013 Amendment 1 told authors that ordering raw text "graduates to the Rego
escape hatch (ADR-0002)". There is no Rego backend: zero `opa`/`rego` module
dependencies, no `rego` property in any frozen v1alpha1 policy schema, no backend
selector. The pointer is replaced by the coercion idioms the same section already
gives (`int(...)`, `double(...)`, `timestamp(...)`), the design-taste sentence is
kept, and Rego is named as planned (E11, D-012) with no implementation today.
`internal/core/aggregate/evaluate.go` carried the same false pointer in a comment
— a second copy the finding did not name — and is corrected with it. This matters
now because D-131's compatibility note ships in the v0.2.0 Release body addressed
to anyone whose policy orders text on purpose: the tag manufactures the readership
that clicks through.

ADR-0002's Status read a plain "Accepted (v2)" while README calls the Rego backend
"Locked — E11" and the C4 page "PLANNED — E11" — the ADR was the only surface
claiming it exists. Annotated.

ADR-0006's Status asserted "CI e2e default: GitLab CE testcontainer". No CI job
boots one: `test/e2e/**` is behind `//go:build e2e` and `verify.yaml`'s only e2e
touch is `go vet -tags e2e ./...`, which compiles and runs nothing.

ADR-0019 §"Multi-replica HA" carries the ADR set's only unmet MUST: `assent doctor`
MUST emit `duplicate_prevention:`. The value is computed (`doctor_forge.go:19`) and
dropped by `emitDoctorReport`. Annotated as unmet rather than emitted: this is one
instance of audit ARCH-11 (doctor prints essentially none of its typed report), so
emitting one field would half-close it and leave the report inconsistent — and a
user-visible CLI output change does not belong in a docs-truth lane.

The ADR index rows for 0002/0006/0009/0019 are updated too. D-135 claimed its
Status extension made the ADR-0009 gap visible on the index; it did not, because
the index is a separate file with its own column — a false claim inside a
correction about a false claim. Leaving 0002/0006/0019's rows plain would have
reproduced exactly that.
…is not shipped

D-134's "Corrected surfaces" clause recommended staying advisory by leaving a
precondition unmet "or `phase: observe`" — advice the same row retracts ~2,000
words later as ARM-08, "false in the unsafe direction, twice over". A reader who
stops at the natural stopping point left with the retracted advice. The clause now
carries the retraction inline. Factual-record correction, not a decision reversal.

D-041 gets a `Superseded by D-134` pointer appended; its content is byte-unchanged
per GUIDELINES (supersede, don't edit).

`vision.md` listed a "local dry-run" among the SHIPPED modes. Measured in this
worktree: `assent run --dry-run` prints `flag provided but not defined: -dry-run`
and exits 2. Corrected to one shipped mode and four planned. Note that the commit
which introduced this (f2f59ed) was itself a docs-truth fix — it split the
paragraph into shipped vs planned and promoted dry-run into the shipped half,
making the false claim stronger and load-bearing.
…-31); OQ-29 to P1

AGENTS.md rule 6 — the audit's reliability and security lenses ruled six P1/P2
findings not blocking for v0.2.0, so the deferral gets written down rather than
carried in a session.

D-138 (RELI-01/02/03): all pre-existing at v0.1.0, verified at 1d8aa60; the
machine direction holds — no probed path merges anything unevaluated — and the
failure is confined to the human signal channel. Records that D-130's
compensating control does NOT reach the GUARD-1 self-edit path, because no thread
is posted there, so nothing holds the merge and no later run repairs the banner;
that RELI-01's fix reopens a frozen acceptance criterion and so is out of release
scope by construction; and that RELI-02 is unrecoverable without a human, with
the race as the declared default posture. Also folds in the ADR-0019
`duplicate_prevention:` annotate-don't-emit call, same human-signal shape.

D-139 (SEC-01/04/05) with the named fixes so the next lane is unambiguous, the
discharged condition that the release must not read as though `--checkout` has
been made safe, and the SEC-05 x SEC-03 composition recorded explicitly AS A
HYPOTHESIS — no evidence real GitLab omits source_project_id. The lens withdrew
its SEC-08 as non-novel (D-130 covers it); not written up.

OQ-31: may the GUARD-1 BLOCK path write a summary or supersession note, and if
not, what channel carries BLOCK to a human given no thread and exit 0? Undecided.
RELI-03 gets no OQ — D11 already decided it; it is unbuilt, not undecided.

OQ-29 raised to P1: its escalation condition ("if docs/architecture/ ever enters
the nav") was already true when written. MkDocs publishes every file in docs_dir
regardless of nav — measured, architecture/policy-profiles/ returns 200, the
sitemap carries 63 locs against ~10 nav entries, and the false invariant is in
search_index.json. GUIDELINES 57-58 is read as a publication boundary but creates
only a nav boundary.

Plus the RELI-03 comment at internal/forge/forge.go, corrected in place: it cited
reset_approvals_on_push as its safety argument, a setting that appears in zero Go
files, and deferred to P4-E1-S10, a slice that shipped. Text only, no behaviour
change — an asserted-and-unbuilt mitigation terminates the search, which is how
this survived two prior audits.
@konih
konih merged commit 876c268 into main Aug 9, 2026
9 checks passed
@konih
konih deleted the lane/audit-pretag-docs branch August 9, 2026 03:23
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