Remove markfluence fix. Its shape is wrong for the use cases it could serve, other commands now cover pieces of it more composably, and #10 will invert the direction it works in.
Sequencing matters and is not settled here. fix --dry-run is currently the only field-by-field comparison of a file against its live page, so removing fix before something else reports drift is a net capability loss even though the write direction is wrong. See "Do this after, not before".
What fix does today
Worth writing down, because the removal should be evaluable rather than taken on faith. It locates the page — by page_id, or by title search when there is no id — then reads the live page, its width and its labels, and writes back into the file's frontmatter: page_id, space, parent, page_width, labels, and a title only when the file's is missing or blank. It also normalizes frontmatter field order, reported separately as reordered. It is read-only against Confluence, and --dry-run previews the whole thing.
Why remove it
#10 inverts its direction, which is the sharpest argument. fix exists to make the file match the page. #10 wants update to enforce space/parent and move pages, which makes the file authoritative for coordinates — so a command whose job is pulling coordinates from Confluence works against the grain. What you want then is "show me where they differ" followed by update to push, not a pull.
Pieces of it are covered more composably. find resolves a title to ids. update pushes the file's truth. info, read and export all display live labels and width. What is unique to fix is not the capability but the write-back orchestration.
It cannot serve #139's central case. A file whose metadata lives in a markfluence.yaml pages: entry has no frontmatter for fix to reconcile, so it currently refuses outright (this file's metadata lives in markfluence.yaml; fix cannot reconcile a pages: entry yet). Making it work means building a nested surgical writer for the manifest — the largest remaining piece of #139's write half — for a command we are proposing to delete.
A read-only verb composes and fix never can. Anything that only reports is safe in CI, a pre-commit hook, a cron, and can exit non-zero when something differs. That is the shape the drift use case actually wants; see #148.
What is lost
Named rather than waved away, because two of these are real.
- Automated repair. "Somebody labeled or moved this page in the UI and I want my file to match" becomes reading a diff and editing by hand. This is the genuine regression.
- Locate-by-title as a workflow.
fix will find your page from its title alone and write the page_id in. Afterwards that is find "Title" plus a paste.
- Frontmatter field-order normalization. Cosmetic, and
create --persist still does it.
What is not lost
No shared code becomes dead. Every helper fix uses has other callers: labels.Read (info, read, pagedoc), pagewidth.Read (update, info, read, pagedoc), client.SearchPagesByTitle (create, find, convert/aclink), jsonout.CodeOr (update, create, attachment-upload, attachfile), pageref.NotFoundMessage/NotNumericMessage (create, update), frontmatter.Normalize (create). So the blast radius really is cmd/fix plus registration, schema and docs.
Scope
cmd/fix/ — ~1,650 lines including tests.
cmd/root.go — registration.
schema/json-output/v1.json — the command enum entry, the fixResult $def, and its if/then branch. cmd's TestCommandEnumMatchesRegisteredCommands and internal/schematest's document tests both close the loop, so a half-removal fails the build rather than shipping.
- Docs:
README.md (6 mentions), CLAUDE.md (6), docs/markdown_file.md (2), docs/json-output.md (2, including the status-verb list), docs/root-model.md (2), docs/guarantees.md (1, under L9 — fix is the example of the opposite-direction asymmetry, so that paragraph needs rewriting rather than deleting), docs/confluence/labels.md, CONTRIBUTING.md, and the generated docs/commands/markfluence_fix.md (make docs).
markfluence is unreleased (1.0.0 still open), so there is no deprecation cycle to design — which is also the argument for deciding this before 1.0 rather than living with the command forever.
Do this after, not before
Removing fix takes fix --dry-run with it, and that is the only thing in markfluence today that answers "how does my file differ from the page?":
! DRY RUN — no changes will be written.
[a.md] set space: ENG -> ~60c36d0718e9f60071326951
[a.md] set parent: 999 -> 76646878
[a.md] set page_width: narrow -> max
[a.md] set labels: [wrong] -> []
So this should land after whatever owns drift reporting — see #148, which records markfluence diff as one candidate shape and deliberately does not pick one yet. Whatever wins should reuse fix's comparison logic rather than reimplement it, and should also close the blind spot fix structurally cannot: a differing title is reported nowhere, because fix correctly declines to change one.
A reasonable order: drift reporting lands → fix is removed → #139's write half needs only create persisting entries.
Related
Remove
markfluence fix. Its shape is wrong for the use cases it could serve, other commands now cover pieces of it more composably, and #10 will invert the direction it works in.Sequencing matters and is not settled here.
fix --dry-runis currently the only field-by-field comparison of a file against its live page, so removingfixbefore something else reports drift is a net capability loss even though the write direction is wrong. See "Do this after, not before".What
fixdoes todayWorth writing down, because the removal should be evaluable rather than taken on faith. It locates the page — by
page_id, or by title search when there is no id — then reads the live page, its width and its labels, and writes back into the file's frontmatter:page_id,space,parent,page_width,labels, and atitleonly when the file's is missing or blank. It also normalizes frontmatter field order, reported separately asreordered. It is read-only against Confluence, and--dry-runpreviews the whole thing.Why remove it
#10 inverts its direction, which is the sharpest argument.
fixexists to make the file match the page. #10 wantsupdateto enforcespace/parentand move pages, which makes the file authoritative for coordinates — so a command whose job is pulling coordinates from Confluence works against the grain. What you want then is "show me where they differ" followed byupdateto push, not a pull.Pieces of it are covered more composably.
findresolves a title to ids.updatepushes the file's truth.info,readandexportall display live labels and width. What is unique tofixis not the capability but the write-back orchestration.It cannot serve #139's central case. A file whose metadata lives in a
markfluence.yamlpages:entry has no frontmatter forfixto reconcile, so it currently refuses outright (this file's metadata lives in markfluence.yaml; fix cannot reconcile a pages: entry yet). Making it work means building a nested surgical writer for the manifest — the largest remaining piece of #139's write half — for a command we are proposing to delete.A read-only verb composes and
fixnever can. Anything that only reports is safe in CI, a pre-commit hook, a cron, and can exit non-zero when something differs. That is the shape the drift use case actually wants; see #148.What is lost
Named rather than waved away, because two of these are real.
fixwill find your page from its title alone and write thepage_idin. Afterwards that isfind "Title"plus a paste.create --persiststill does it.What is not lost
No shared code becomes dead. Every helper
fixuses has other callers:labels.Read(info,read,pagedoc),pagewidth.Read(update,info,read,pagedoc),client.SearchPagesByTitle(create,find,convert/aclink),jsonout.CodeOr(update,create,attachment-upload,attachfile),pageref.NotFoundMessage/NotNumericMessage(create,update),frontmatter.Normalize(create). So the blast radius really iscmd/fixplus registration, schema and docs.Scope
cmd/fix/— ~1,650 lines including tests.cmd/root.go— registration.schema/json-output/v1.json— thecommandenum entry, thefixResult$def, and itsif/thenbranch.cmd'sTestCommandEnumMatchesRegisteredCommandsandinternal/schematest's document tests both close the loop, so a half-removal fails the build rather than shipping.README.md(6 mentions),CLAUDE.md(6),docs/markdown_file.md(2),docs/json-output.md(2, including the status-verb list),docs/root-model.md(2),docs/guarantees.md(1, under L9 —fixis the example of the opposite-direction asymmetry, so that paragraph needs rewriting rather than deleting),docs/confluence/labels.md,CONTRIBUTING.md, and the generateddocs/commands/markfluence_fix.md(make docs).markfluence is unreleased (1.0.0 still open), so there is no deprecation cycle to design — which is also the argument for deciding this before 1.0 rather than living with the command forever.
Do this after, not before
Removing
fixtakesfix --dry-runwith it, and that is the only thing in markfluence today that answers "how does my file differ from the page?":So this should land after whatever owns drift reporting — see #148, which records
markfluence diffas one candidate shape and deliberately does not pick one yet. Whatever wins should reusefix's comparison logic rather than reimplement it, and should also close the blind spotfixstructurally cannot: a differingtitleis reported nowhere, becausefixcorrectly declines to change one.A reasonable order: drift reporting lands →
fixis removed → #139's write half needs onlycreatepersisting entries.Related
markfluence status, and themarkfluence diffalternative for drift. The prerequisite in practice.updateenforcing space/parent and supporting moves; the reasonfix's direction stops making sense.pages:entries. Removingfixdrops the manifest writer's hardest consumer.updatesilently overwriting a Confluence-side edit; the recorded-version state it needs is what would make drift reporting exact rather than timestamp-based.