Repository navigation
Conversation
hackmd_create_note forwarded comment_permission and suggest_edit_permission, which HackMD drops on create (201, read back null) and rejects on PATCH (422). Create now refuses them before any request, as update already did, and both point to the web UI, so neither tool appears to set something that never takes.
The plain /notes/{id}/images route accepts a team note by its internal
id (measured 2026-10-06), so the team refusal goes. team_path stays
accepted but unadvertised: the route ignores it, and it only
cross-checks the owner of an @owner/slug URL. Upload still requires a
workspace root, since an image on a guest-readable note is public.
The destructive suite now uploads through that route to an owner-only
team note and asserts an anonymous fetch of the image is refused,
instead of asserting the team-prefixed route is absent. PNG_PROBE gets
its correct IDAT checksum, so every live upload sends a valid image.
folderPaths read a missing field as an empty list, so a read that omitted it, as a team note read may, confirmed a move to the root that never happened. The field is now an Option, and only a read that lists no folders confirms the root.
A read_permission HackMD drops leaves the note at a default that may be more open than asked, and create never checked. It now compares the tags, description, permalink, and permissions it sent against the note it returns, sharing update's comparison, and polls only on a mismatch. What never shows is listed in unconfirmed_fields, never raised as an error: the note exists, and an error would invite a duplicate create. An empty permalink now matches null, as clearing it may read back. The destructive suite prints the permissions a create without them gets and asserts a team create's owner permissions show.
HackMD stores any order map it is sent and reads it back intact, so the read-back confirmed orders of unrelated or made-up IDs. child_order now refuses an ID that hackmd_list_folders does not show as a direct child of folder_id, and a named parent that does not exist, before anything is written. Every folder input check now runs before the first request. The check is best effort: HackMD has no conditional write.
A cleared folder field may read back as an empty string, and an icon or color in another case, so a write that landed was reported as a read-back mismatch. The comparison now treats null and empty as equal and compares icon and color ignoring case.
Without note_ref the sync record names the note, so a team_path naming another workspace means the caller has the wrong file or note in mind. Push now refuses it before any request. A matching team_path and refresh are still ignored, as they always were, so no existing caller breaks.
Tool descriptions, field docs, and docs stated as fact what nobody has measured: patches keeping metadata, folder fields being preserved, team deletions being permanent, personal folder PATCH not existing, history order, an unversioned body, and a 5 MB image limit. Each now states only what was measured, and the reason a refusal gives is the measured one. note_features is documented as forwarded unchecked. The destructive suite uploads a 7 MiB image, padded with a private ancillary chunk so it stays a valid PNG, to measure the size limit.
The docs named CLAUDE.md as an example of the files a pull refuses to overwrite. They now list AGENTS.md and SKILL.md and say an instruction file can import any Markdown file. The deny-list itself is unchanged.
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.
Several tools reported or implied that HackMD did something nobody had shown it does. The worst case: hackmd_create_note forwarded comment_permission and suggest_edit_permission, which HackMD drops on create, and never checked read_permission, so a dropped owner-only permission left a note more open than asked with no warning. Create and update now refuse the two unsettable permissions. Create compares what it sent against the note it returns and lists anything that never shows in unconfirmed_fields; that is never an error, because the note exists and an error would invite a duplicate create.
Image upload now serves team notes through the same /notes/{id}/images route, which accepted a team note when measured on 2026-10-06. The same sweep closed other checks that could pass without proof: a read without folderPaths confirming a move to the root, child_order confirming IDs that are not children of the folder, and folder read-backs failing over null versus "" or letter case. Push without note_ref refuses only a team_path that contradicts the sync record, so callers passing the note's own team keep working. Tool descriptions and docs now claim only what was measured.
Verified with
cargo test --all-targets --all-features(286 unit, 11 stdio; the live suites are ignored by design) andcargo clippy --all-targets --all-features -- -D warnings, both clean. Codex and Claude reviewers checked each round.Not verified: the claims the destructive live suite exists to settle. It now prints or asserts the default permissions a create gets, a team create's owner permissions, a 7 MiB image upload, the plain-route team upload, and that an anonymous fetch of an owner-only note's image is refused. It has not been run for this change; it needs the dedicated throwaway account.
Summary by cubic
Create now confirms what it sent.
comment_permissionandsuggest_edit_permissionare refused on both create and update, because the API drops or rejects them; a droppedread_permissioncould leave a note more open than asked, so create polls until the sent fields show and lists anything that never does inunconfirmed_fields(tags, description, permalink, and the two permissions only), never as an error. Image upload serves team notes through the plain/notes/{id}/imagesroute, which was measured to accept them. Checks that could pass without proof are closed: a read omittingfolderPathsno longer confirms a move to the root,child_orderrefuses IDs that are not direct children of an existing folder, folder read-backs toleratenull/""and case differences, and push withoutnote_refrefuses ateam_pathcontradicting the sync record. Tool descriptions and docs now claim only what was measured; the 5 MiB image limit and other unmeasured behaviors are stated as unmeasured.Written for commit b92285d. Summary will update on new commits.