fix(generate): unwedge docs-sync and correct the MCP security model - #90
Merged
Merged
Conversation
The auto-sync pipeline has not produced a PR since 2026-08-05. Six open "Auto-sync generation failure" issues trace to two permanently unsatisfiable manifest entries, not to transient failures. 1. `live-class` (harper-mcp/custom-mcp-tools) has never existed in the MCP docs — `git log -S` across all of reference/mcp/ finds no commit that ever added it. Because lib/llm.mjs echoes must_cover to the model as "MUST include ... verbatim", the anchor did not merely fail: when it passed, it passed because the model coined the term. The shipped rule carried "Dispatch is live-class. Calls construct an instance of the class currently in the Resource registry ..." — a sentence with no counterpart anywhere in the sourced section. That is the anchor manufacturing content, then validating it. Replaced with `allow*`, which is in the source and pins the security fact. 2. `Module Loading` (custom-resources, programmatic-table-requests) was renamed to `Module Formats` by documentation#664 on 2026-09-04. The section is sourced for one thing — keep `harper` external when bundling for SSR — and `vite.config` moved with the rename, so the new heading is a like-for-like replacement. 3. `getContext()` (checking-authentication) was unsatisfiable a third way: the anchor demanded a string that appears in no sourced section. `getContext()` occurs seven times in resource-api.md, none of them inside `getCurrentUser()` or `Session and Login from a Resource`, and zero times in the JWT source. The model could only satisfy it by inventing, which the system prompt forbids, so every run failed validation. Added the `getContext(): Context` section, which carries the instance-vs-static contract the rule needs anyway. Regenerated the four affected rules against documentation@9e6ecf8. The MCP regeneration also fixes live-wrong security guidance on main: the rule claimed data access inside a custom tool "still hits per-record `allow*` predicates", where the docs now say the transport "invokes the custom instance method directly ... does not open a Resource transaction or run an `allow*` gate automatically". An agent trusting the old sentence shipped ungated table access on an anonymously reachable tool. The fact-retention check from #86 earned its place immediately: it caught eight dropped facts across these four regenerations. Two were restored by anchoring (the literal `HdbError: <attribute> is not indexed ...` string an agent matches a runtime failure against, and `npm link harper`); six were judged notation rather than content and waived in `allow_dropped`, each with its reasoning recorded inline. Also closes the remediation loop the check points at. `inputHash` covers resolved sources only, so editing `must_cover` left it matching and the rule was skipped — the new anchor never reached the model and validate-generated then failed on it forever. Generation now also regenerates when the body on disk does not satisfy its own anchors. Verified: breaking an anchor in a body triggers regeneration with no --force. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 8, 2026
Contributor
There was a problem hiding this comment.
Code Review
This pull request updates the Harper and Harper MCP best practices documentation, rule manifests, and the rule generation script to improve clarity, structure, and accuracy around authentication, custom resources, and programmatic table requests. The review feedback correctly identifies that the documentation incorrectly references the deprecated harperdb-config.yaml instead of the canonical harper-config.yaml for Harper v5, which would lead to silent configuration failures.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
github-actions Bot
pushed a commit
that referenced
this pull request
Sep 8, 2026
## [1.12.10](v1.12.9...v1.12.10) (2026-09-08) ### Bug Fixes * **generate:** unwedge docs-sync and correct the MCP security model ([#90](#90)) ([e98efec](e98efec)), closes [documentation#664](HarperFast/documentation#664) [#86](#86)
|
🎉 This PR is included in version 1.12.10 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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.
The auto-sync pipeline has not produced a PR since 2026-08-05. The six open "Auto-sync generation failure" issues (#73, #83, #85, #87, #88, #89) are not six transient failures — they are two permanently unsatisfiable manifest entries plus one broken reporter.
Why every run failed
must_cover: live-class— a term that has never existed in the MCP docscustom-mcp-toolsmust_cover: getContext()— absent from every sourced sectionchecking-authenticationsection: Module Loading— renamed by documentation#664custom-resources,programmatic-table-requestslive-classwas manufacturing content, not just failinggit log -S'live-class' --all -- reference/mcp/finds no commit that ever added it. Andlib/llm.mjsechoesmust_coverto the model as "The rule body MUST include each of the following (verbatim for code/identifiers)" — so when this anchor passed, it passed because the model coined the term. The shipped rule carries:Nothing in the sourced section mentions a registry, a subclass, a reload, or a deploy. The anchor invented the sentence and then validated it. Replaced with
allow*, which is in the source and pins the security fact instead.getContext()was unsatisfiable a third wayIt occurs 7 times in
resource-api.md— none inside`getCurrentUser()`orSession and Login from a Resource, and 0 times in the JWT source. The model could only satisfy it by inventing, whichsystem-prompt.mdforbids, so the run failed validation every time. Fixed by sourcing the`getContext(): Context`section, which carries the instance-vs-static contract the rule needs anyway.Module Loading→Module Formatsdocumentation#664 renamed the heading (it described ESM vs CJS, not module loading) and split real module-loading docs into a new page. The section is sourced for exactly one thing — keep
harperexternal when bundling for SSR — andvite.configmoved with the rename, so this is like-for-like.Live-wrong security guidance, now corrected
Regenerating
custom-mcp-toolsfixes something worse than a wedged pipeline. The rule onmainsays:The docs say the opposite:
An agent trusting the old sentence ships ungated table reads and writes on a tool reachable by anonymous, unauthenticated MCP sessions. The regenerated rule states the negative list correctly and picks up the
checkPermission/ fresh-RequestTargetguidance added upstream.The retention check earned its place immediately
#86's fact-retention gate caught 8 dropped facts across these four regenerations. Two were real and restored by anchoring:
HdbError: <attribute> is not indexed and not combined with any other conditions— the literal string an agent matches a runtime failure against. Regeneration had reduced it to "throws an error".npm link harperSix were notation rather than content and are waived in
allow_dropped, each with its reasoning recorded inline:authentication.enableSessions: true(same fact as YAML + prose),{param}(replaced by a concrete/widget/{id}/action/{action}example),databases, and thetxntable's Type column (() => Promise,() => void,number— all four members and their behavior survived).Known limitation, stated plainly: that last group is the check's noise floor. It compares code spans, so a dropped table column reads the same as a dropped fact, and
numberis too generic to pin anything. Waiving is the intended response and stays visible in review.Closing the remediation loop
The check tells you to "restore them", and anchoring is how — except it didn't work.
inputHashcovers resolved sources only, so editingmust_coverleft it matching, the rule was skipped, the new anchor never reached the model, andvalidate-generatedthen failed on it forever. Generation now also regenerates when the body on disk fails its own anchors. Verified: breaking an anchor in a body triggers regeneration with no--force.Verification
npm run validategreen.validate-generated.mjs --docs-path <docs@9e6ecf8>green, including source-exists, byte-identical and fact-retention.9e6ecf8(docsmain), so the rules are not born stale.Not in this PR
reference/resources/resource-api.mdstill says`harperdb-config.yaml`in the sessions section, which documentation@d895f428 was meant to eliminate. The regeneratedchecking-authenticationfaithfully reproduces it. That is an upstream docs fix, and worth doing before the next sync picks it up again.🤖 Generated with Claude Code