Cut the README from 1534 to 531 lines, and make --help the command reference - #145
Merged
Conversation
The largest single subsection of the README (243 lines, 16% of the file) was a construct-by-construct reference for what the converter does with each markdown element. Nobody reads that top to bottom; they look one construct up. Moved verbatim to docs/markdown.md, where docs/confluence/ and docs/guarantees.md already live. The README keeps a short pointer naming what is supported and what is lossy, which is what a reader skimming it actually needs. Content moved unchanged on purpose. Retitling or restructuring it in the same commit would make the diff unreviewable as a move, and the bold run-in headings it uses are worth revisiting separately -- 240 lines under one heading is not much more navigable than it was in the README. Five README anchors pointed into the moved section (#body) and now point at the new file. Part of #102.
The scopes section carried a second copy of docs/confluence/api.md's scope material, and the README was the lossier copy -- 3 occurrences of granular scope names against api.md's 12. It was a live drift risk rather than a theoretical one: #91 required updating the README's per-command scope table, and code review caught that a row had been missed. Kept what somebody configuring a token needs at hand: when a cloud ID is required and why, how to find it, the copy-pasteable scope list, that scopes are fixed at issue time, that the mixed vocabularies are deliberate, and a 401-vs-403 table -- which is the one genuinely actionable diagnosis and was buried in prose before. Dropped what api.md owns and covers in more depth: the per-command scope table (which scope each call needs, with provenance), the full classic/granular explanation, and the token-probing recipe -- api.md has that with the story of how the first scoped service-account token's missing scope was found. 92 lines to 57. Part of #102.
A hand-written TOC would duplicate something GitHub already renders -- the outline button on any markdown file -- and would become one more place to update when a section is added. That is the failure mode the two previous commits removed: the scope table rotted because it was a second copy. What GitHub's outline cannot do is index the other files, and "where is the thing about X" is the actual question, with X often living in docs/markdown.md or docs/confluence/. So this points across the doc set rather than mirroring this file's own headings, and names --help as the authoritative per-command description. Top-level entries are stable enough not to rot. Part of #102.
Each command's cobra long description already carries its reasoning, and these three repeated it nearly verbatim -- children's "a folder can hold the only pages in a subtree" and "a folder counts as a level", search's ANDing and archived-pages-are-invisible, export's --depth and --space walks. Removed from the README, which now points at `markfluence COMMAND --help` for the why. Kept what --help cannot carry and a reader genuinely wants: example invocations, sample output, and the details that are not in the help text (search's excerpt highlighting, export's markfluence.yaml and the absent --attachments-dir, children's output alignment and the stderr depth hint). 78+88+77 = 243 lines down to 198. Worth recording that this is less than claimed: the estimate on #102 was ~300 lines for this step across all commands, derived from 227 lines of --help prose existing. That conflated "help prose exists" with "the README duplicates it". These were the three most duplicative sections and they yielded 45 lines, so the remaining ten are worth perhaps 40 more, not 250. Part of #102.
The --json section was 124 lines, the second-largest in the file, and most of it was a field-by-field walkthrough: per-command status verbs, what counts as one result for each command, check's broken semantics, create's preflight abort, search's summary extras. Moved rather than deleted, which is what #102 originally proposed. The schema at schema/json-output/v1.json is the authoritative contract and a test validates real output against it, but the schema cannot carry the *reasoning* -- why check's broken status has no error/code (its broken/warnings arrays already say everything), why find and search report an operational failure on stderr rather than as a result (an empty results array would be worse, since "no matches" is an answer a caller acts on). That belongs somewhere, just not in the README. The README keeps what a script author needs at hand: what --json is, a jq example, the worked envelope, and the exit codes -- now a table rather than prose, since which of 0/1/2 you get and whether an envelope is on stdout is the most actionable thing in the section and was the hardest to find. 124 lines to 73, with 71 moved. Part of #102.
The README's Development section duplicated CONTRIBUTING.md line for line -- Go 1.25+, make build/test/check, "run make with no target", and putting a .env in the working directory were all already over there, several with more detail. It ended by linking to CONTRIBUTING.md for the rest, which made the duplication its own argument. Now a pointer that names what is over there, so a reader can tell whether to click. Also removes a claim CONTRIBUTING.md should no longer make: it asked a bug reporter to "say which Confluence flavor you're on (Cloud or Data Center), since the API differs". markfluence now states that Data Center is unsupported, so asking would invite a report we have already said we cannot act on. Includes uncommitted wording and formatting edits to the Configure and scopes sections that were already in the working tree -- not mine, carried along rather than reverted. Part of #102.
Retitled to "Using with GitHub Actions", which says what it is rather than naming a product, and moved out of the README: it is a task somebody follows once while wiring up CI, not something a reader of the README needs in front of them. The README keeps a pointer naming what is over there -- a working workflow, credential storage, and the service-account argument -- so a reader can tell whether to click. Its two cross-references into the README (scoped tokens, --json output) now point back at ../README.md, and its opening paragraph loses the sentence the README's pointer now carries, keeping only the fact a reader needs: you have to know each page's page_id. 75 lines out of the README, which is now 1108 -- down from 1534 when #102 was picked up. Part of #102.
The file arrived as one "Supported constructs" section with bold run-in headings, which meant 240 lines under a single heading and nothing for GitHub's outline to show -- not much more navigable than it was inside the README. Now eleven headings, with the three table topics nested under Tables since that is the actual structure: fenced code blocks, tables (cell background colors, multi-line cells, lists in cells), GitHub alerts, images, links to other pages, comment directives, and raw storage format. Also fixes two links this file's own move broke. Both "(#the-documentation-root)" anchors pointed at a README section that stayed in the README, so they resolved to nothing here -- when the section moved I checked the README's anchors pointing *in* and not this file's pointing *out*. Three dangling GFM reference links folded into the sentences they belong to, where they had been left stranded at the end of a paragraph by the original prose style.
A mention is a body construct, the same as an image or a link, so it belongs with the others. Two signs it was misplaced: it sat under "Markdown page structure" immediately beside *frontmatter*, and docs/markdown.md already referred to mentions in passing -- "a mention, an attachment link, or an external URL was never meant to resolve here" -- while not documenting them. Placed directly after "Links to other pages", because a mention *is* a link form and the two explain each other: that section's closing sentence now hands off to it rather than naming a construct the reader has no section for. The README's Body pointer names mentions and the table-cell conventions, so a reader skimming it knows those are covered rather than missing. README 1109 -> 1072, down from 1534 when #102 was picked up. Part of #102.
The file was the body half of a reference whose other half -- the frontmatter block -- was still in the README, and its intro had to say so. Both halves now live together: what a markfluence markdown file is, every frontmatter field and what each verb does with it, then every body construct. Named markdown_file.md rather than markdown_page.md because the subject is the file. A reader has one open in their editor and wants to know what goes in it; the page is the result, and the doc's own first line is "each Markdown file is one Confluence page". Headings nest to match: Frontmatter and Body as the two halves, with the constructs under Body. Body as a *peer* of Tables read wrong -- the constructs are the body. The README keeps the shape (the annotated example block, which is what somebody skimming wants) plus a pointer. 66 lines to 24; README 1074 -> 1032, down from 1534 when #102 was picked up. Part of #102.
Every command now carries its own reasoning and a worked Example block, so `markfluence CMD --help` answers what it does, why, and how to invoke it. Cobra has an Example field for exactly this and **no command used it** -- the README was carrying content the binary had a dedicated, empty slot for. The Long descriptions absorb what only the README said: create's page_id-that- resolves-to-nothing being a failure rather than a fresh page and what a run interrupted after the reserve phase leaves behind; update's never writing back (so fixing a wrong id is always safe) and the mtime skip; fix's canonical key order and that labels are reconciled even for a file with no labels: line; read's lossy transforms making it a reading aid rather than a guaranteed round-trip; info's omitted-empty-fields rule. Also adds TestSubcommandsDocumentThemselves, which is what makes --help usable as *the* reference rather than one of two places. The move creates a new way to regress -- a command added with a one-line Long and no Example would be documented nowhere and nothing would notice -- so the test requires both. A length floor rather than non-empty, since "Create pages." satisfies non-empty and explains nothing. The README still duplicates much of this; that comes out next. Part of #102.
…commands/ ## Usage was 736 lines of per-command reference. It is now 200: which command to reach for, a typical workflow in both directions, and the three output shapes worth seeing before you run them (children's indented tree, find's three-way current/archived/folder split, search's hit blocks). Everything else moved into the commands themselves in the previous commit. The README should be a 50' view of what markfluence can do and which command is used for what. It should not be a command reference -- that is what `markfluence CMD --help` is for, and keeping both meant keeping them in step, which is the failure this issue has been unwinding. docs/commands/ is that help text rendered to markdown by cobra's own doc generator, so the reference is browsable and linkable on GitHub without installing anything. Generated and checked in, which is a second copy -- and only acceptable because it cannot drift: `make docs-check` regenerates into a temp dir and diffs, and it runs inside `make check`, the same role fmt-check plays for formatting. DisableAutoGenTag, or a timestamp would make every regen a diff and turn the guard into noise. cmd.Root() is exported for the generator alone. A main() inside package cmd would be built into the binary, and a _test.go that writes files into the repo is not a test. Two things the sabotage test of the guard caught, which is the argument for testing a guard rather than trusting it: `make docs` silently did nothing, because docs/ is a real directory and make considered the target satisfied (missing .PHONY); and the diff output needed to name the file, or "out of date" tells you nothing about what to look at. README 1017 -> 481, from 1534 when #102 was picked up. Part of #102.
Two changes to the README's narrative sections. **A fix workflow.** fix is the only command whose direction is opposite to every other -- it writes to your files from Confluence -- and nothing demonstrated it, which makes it the command most likely to surprise somebody later. Shows the --dry-run first, since "what disagrees?" is the question you actually have, and names the asymmetry it settles: update leaves a field alone when your file does not mention it, while fix fills that field in from the page. It also states what fix does *not* do. A first draft of this said fix adopts a page somebody "labeled or retitled" in the UI. Checking the code rather than trusting the sentence: plannedChanges fills a title only when the frontmatter's is missing or blank, so a page renamed in Confluence does not rename your frontmatter. Worth saying outright, because "reconciles the file to the page" invites exactly that assumption. **Common tasks becomes ### Moving files and assets, under The documentation root.** It was a top-level section sitting next to "Common workflows" while being a different kind of thing entirely: it contains no commands at all, and all its entries are consequences of the root and identity model the section above establishes -- which is what made the two similar names confusing. Now it reads as the consequences half of that section, and is titled for what it is. Its fourth entry is dropped. "Setting up a shared assets directory needs a markfluence.yaml at the shared root" restated what the root section says two paragraphs above it.
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.
README.md was 1534 lines. It is now 531 — a 65% cut with nothing deleted that wasn't duplicated elsewhere, better placed elsewhere, or already available from the binary. Fixes #102.
The shape it converges on: the README is a 50,000-foot view of what markfluence can do and which command to reach for. It is not a command reference — that is what
markfluence CMD --helpis for. Keeping both meant keeping both in step, which is the failure this issue was really about.Where the lines were
Measured first, because the distribution mattered more than the total:
## Usage— per-command reference## Markdown page structure## Configure--helpbecomes the referenceCobra has an
Examplefield for worked invocations and no command used it — the README was carrying content the binary had a dedicated, empty slot for. Every command now has one, and theLongdescriptions absorbed what only the README said:create's page_id-that-resolves-to-nothing being a failure rather than a fresh page;update's never writing back, which is why fixing a wrong id is always safe;fix's canonical key order;read's lossy transforms making it a reading aid rather than a guaranteed round-trip.## Usageis now which command to reach for, three common workflows, and the three output shapes worth seeing before you run them (children's indented tree,find's current/archived/folder split,search's hit blocks).docs/commands/is that help text rendered by cobra's own doc generator, so the reference is browsable and linkable on GitHub without installing anything. Generated and checked in — which is a second copy, and only acceptable because it cannot drift:make docs-checkregenerates into a temp dir and diffs, and runs insidemake check, the same rolefmt-checkplays for formatting.DisableAutoGenTag, or a timestamp would make every regeneration a diff and turn the guard into noise.TestSubcommandsDocumentThemselvescloses the loop. Once--helpis the reference, a command added with a one-lineLongand noExampleis documented nowhere and nothing else would notice. It requires a length floor rather than non-empty, since"Create pages."satisfies non-empty and explains nothing.What moved out
docs/markdown_file.mddocs/json-output.md--jsondetail. The schema is the authoritative contract but cannot carry reasoning — whycheck'sbrokenhas noerror/code, whyfind/searchreport failures on stderr rather than as a resultdocs/github-actions.mdWhat was deleted as duplication
### Scoped tokenscarried a second copy of docs/confluence/api.md's scope material, and the README was the lossier copy — 3 occurrences of granular scope names against api.md's 12. A live drift risk, not a theoretical one: #91 required updating the README's scope table and code review caught that a row had been missed.## Developmentduplicated CONTRIBUTING.md line for line, then ended by linking to CONTRIBUTING.md for the rest — the duplication was its own argument. It became a pointer, then went away once CONTRIBUTING.md earned a row in the index table.Three command sections repeated their own
--helpalmost verbatim before the wholesale move.Structure
A "Location of documentation" table instead of a hand-written TOC. GitHub already renders an outline for any markdown file, so a TOC duplicates it and becomes one more thing to update — precisely the rot that made the scope table wrong. What GitHub's outline cannot index is the other files, and "where is the thing about X" is the actual question.
### Moving files and assetsmoved under## The documentation root. It was top-level and next to "Common workflows" while being a different kind of thing: no commands in it at all, every entry a consequence of the root and identity model that section establishes.Three things worth flagging
My estimate for the
--helpde-duplication step was wrong. I projected ~300 lines on #102 from "227 lines of--helpprose exist" — which conflated existing with being duplicated. Hand-trimming three sections yielded 45. What actually delivered was moving the reference wholesale and letting--helpown it.Testing the drift guard found two bugs in it.
make docssilently did nothing, becausedocs/is a real directory and make considered the target satisfied — a missing.PHONY. Without sabotaging it deliberately I would have shipped a regenerate target that never regenerates. The failure message also needed to name the file.A claim in the
fixworkflow was wrong and I checked rather than trusted it. A draft saidfixadopts a page somebody "labeled or retitled" in the UI.plannedChangesfillstitleonly when the frontmatter's is missing or blank, so a renamed page does not rename your frontmatter. The README now says that outright, because "reconciles the file to the page" invites exactly that assumption.Also here
cmd.Root()is newly exported, for the docs generator alone — amain()inside packagecmdwould be built into the binary, and a_test.gothat writes files into the repo is not a test. That is new public surface for a tooling concern, and worth a look.CONTRIBUTING.mdno longer asks a bug reporter which Confluence flavour they are on "since the API differs" — markfluence now states Data Center is unsupported, so asking invites a report we have said we cannot act on.Docs and help text only — no behaviour change, and
make checkpasses at every commit.