feat(open-knowledge): validate frontmatter against JSON Schema (#2919)#817
Merged
Conversation
* docs(open-knowledge): frontmatter data contract spec, evidence, and story catalog Carried over from theming-as-plugin so the frontmatter validation work can be kicked off from main later. Brings the durable data contract spec with its worldmodel evidence, the doc-patterns / property-schemas / linting story catalog it serves, and the lint-plugins ecosystem-standard seam spec it is grounded in. Implementation, themes, markdownlint, and the plugin research reports stay behind on the old branch on purpose; four report links inside the seam spec dangle as a result. * docs(open-knowledge): carry the Vale/remark-lint engine survey report The frontmatter data contract's worldmodel evidence cites this report twice as the internal engine survey behind the ajv / JSON Schema decision (buy the engine, keep the thin data layer; parse is not validate). It was the only branch-only report the contract leans on; the other cited reports already live on main. Its link to zed-vscode-rule-management-architecture dangles on the source branch as well, so it is carried unchanged. * docs(open-knowledge): flatten frontmatter config key to contentRules.frontmatter The plugins nesting level between contentRules and frontmatter carried no data or behavior of its own and is being removed in the linter work; the contract example now shows the flattened path and notes that branch-era evidence still shows the old nesting. * docs(open-knowledge): worldmodel groundings — schema-rules file location + agent read-time schema discovery Two fresh /worldmodel runs on the frontmatter data contract, per review feedback. First: whether schema rules belong inside .ok/config.yml or in separate files, re-derived from prior art without anchoring on the spec's pinned shape (web survey of four persistence shapes, current-tree and branch code, internal reports, LANDSCAPE seed). Second: how agents interact with glob-scoped schemas and what conventions exist for making a doc's schema known at read time before a write (harness-resolved globs, fetch-schema-before-write, validate-repair loops, OK's current MCP read/write surfaces). Observational only; divergences flagged, including spec-glob vs branch-regex appliesTo and the not-yet-implemented write-advisory ride-along. * docs(open-knowledge): reframe branch-code divergences as provenance notes The theming-as-plugin implementation is reference-only and will not merge; the rebuild starts from origin/main. The glob appliesTo and flattened config nesting decisions in the contract are normative, so the evidence docs now record the old code's regex matching and plugins nesting as provenance, not open questions. * docs(open-knowledge): ground the two-file-split question (rules.yml vs contentRules block) The file-location worldmodel answered where schema content lives but not the sharper question the feedback asked: is there prior art for a dedicated rules file next to the main config within one tool. Adds a re-probe: both currents are mainstream (markdownlint-cli2, golangci, Claude/Cursor rules dirs split; ESLint flat, Biome, Deno, Cargo lints consolidate), with the documented predictor being portability to other consumers, cascade scope, and mechanism class rather than fashion. * docs(open-knowledge): ratify D7 (rules stay in config.yml) + D8 (templates-pattern agent surfaces) Folds the two 2026-07-14 grounding outcomes into the contract: a decision entry confirming the contentRules block belongs in config.yml rather than a dedicated rules.yml (the prior-art predictors for a separate file do not hold), and a new serving-surfaces section pinning how agents learn applicable schemas — OK resolves appliesTo as the harness, read enrichment advertises schemas the way templates_available does today, write advisories cover the new-file gap, lint stays the on-demand audit. * docs(open-knowledge): cold-reader audit findings for the frontmatter contract doc set 17 findings (4 high, 7 medium, 6 low) from a fresh-context audit running coherence lenses and factual verification over the SPEC, its evidence files, the story catalog, and the seam spec. Headliners: the example schemas' https draft-07 $schema URI is unknown to ajv and would schemaError under the contract's own D2 rule; the branch DOES already ship the frontmatter write-advisory (computeLintViolations, cap 10) contradicting the SPEC's greenfield claim; the schema file path base is stated as both project-root-relative and content-dir bounded; and the primary evidence snapshot still presents regex appliesTo as decided. Findings only, nothing fixed. * docs(open-knowledge): greenfield the contract; fix $schema URIs; stamp stale evidence Audit findings 1, 2, and 4. Examples now carry the canonical http://json-schema.org/draft-07/schema# URI (ajv rejects the https form) and D2 pins the accepted alias set. The spec no longer grounds itself in the discarded theming-as-plugin prototype: the branch-relative deltas section is gone (all five items were already ratified as D1, D2, D4, D6), the sign-off ratifies a greenfield implementation off main, and the prototype survives only as provenance in the evidence files. The agent-discovery evidence gets an erratum (the prototype DID ride frontmatter violations on write advisories via computeLintViolations, capped at 10), and the 2026-07-13 snapshot gets a provenance stamp marking regex-appliesTo and the plugins nesting as superseded. * docs(open-knowledge): fix path base to project root; real glob dialect name; seam-spec supersession notes Audit findings 3 (option i: file resolves from and is bounded by the project root, so .ok/schemas/ works under any content.dir), 5 (the dialect is globby/picomatch set semantics, not gitignore re-inclusion), and 11 (the seam spec now marks its regex appliesTo and forbid keys as superseded by data-contract D1/D6). * docs(open-knowledge): pin dedup key, config-channel errors (D9), defaults + implicit-** rule Audit findings 7, 8, 9, per review. Dedup identity is the resolved schema-file path (byte-identical distinct files deliberately validate twice). New D9: schemaError and invalid-glob problems surface on the config channel (settings panel, top-level warnings on lint responses, CLI stderr), never as per-doc diagnostics; per-doc anchoring gains the line-1 fallback for root-level errors and fence-less docs. The slice pins enabled: true as default with an absent block meaning inert enabled-with-zero-schemas, and degenerate appliesTo sets get one rule: no positive glob means an implicit **, so negation-only lists carve out rather than match nothing. * docs(open-knowledge): settle the NG1 [NEVER] reading (D10) + pin the write-advisory cap Audit finding 10, both halves. New D10 settles the nested-frontmatter spec's NG1 tag by intent: it forbids blocking enforcement, and this contract is advisory-only on every surface — violations warn, never gate a write; making them gate is a posture-breaking change. NG1 itself gains a cross-pointer recording the settled reading. The agent write-advisory pins the cap: at most 10 violations per write response, full set on lint. assessment.md's discharged claim is now true. * docs(open-knowledge): sweep the five low-severity audit findings Verdict ownership moved to the spec (the groundings stay observational), D8's harness-resolves-globs headline carries its qualification, the schemas comment no longer implies entry-order precedence, the no-doc-path jargon is glossed, the worked example shows the actual offending value, the 'is exactly JSON Schema' quote is reattributed to the seam spec, and the repair-loop percentages now cite their study. * docs(open-knowledge): present the spec as the proposed contract, not its changelog Strips the internal dialog: no feedback-round narration, no earlier-draft blockquote, no discarded-prototype asides, no revisited/reaffirmed parentheticals. Grounding collapses to one statement pointing at the evidence worldmodels, and the revision history lives in git and the evidence files. * docs(open-knowledge): cite agents manage-ui JsonSchemaEditor as GUI prior art * docs(open-knowledge): ground the frontmatter contract against the shipped plugin PR PR #2433 landed the substrate on main, so re-ground the doc set against shipped code rather than the worktree prototype: - SPEC header: the registry, LSP diagnostics, async lint(), advisory channel, MCP lint + ok lint, and Plugins settings shipped; only the frontmatter artifacts remain greenfield. - Advisory asymmetry claim corrected (P6, D5, the derived-behavior note): the shipped channel carries every enabled lint source, markdownlint included, capped at 10; the data-vs-style distinction now lives in per-plugin enablement. - D9 aligned to the shipped warnings[] surfaces (audit response, MCP structured payload, ok lint report lines). - Flagged the enabled-default tension for approval: shipped registry convention is default-OFF opt-in; the contract proposes default-on. - assessment.md + agent-schema-discovery evidence: post-ship corrections (advisory widened not frontmatter-scoped; rules.yml/errorRuleIds retired; cli2 cascade shipped). * docs(open-knowledge): frontmatter plugin defaults off, matching the registry convention Resolves the flagged enabled-default question: no default-on carve-out. The frontmatter plugin is enabled the same way every other lint plugin is (Settings -> Plugins, contentRules.frontmatter.enabled, default false); an absent block means off. * [US-001] core appliesTo glob matcher (picomatch, set semantics, invalid-pattern reporting) * [US-002] core frontmatter validation engine (ajv draft-07, key-line anchoring) * [US-003] register the frontmatter lint plugin (registry, slices, config leaf) * [US-004] server frontmatter schema-file resolution and injection * [US-005] frontmatter results + config warnings across the lint surfaces * [US-006] ok lint validates frontmatter headless * [US-007] MCP read-time schema advertisement (exec enrichment) * [US-008] settings panel: frontmatter schema mappings editor * [US-009] non-destructive schema-file write path (applyFieldConstraint + endpoint) * [US-010] settings GUI: per-field schema editor * [US-011] property panel renders schema-driven enum selects * [US-012] changeset, knip and lint sweep for the frontmatter plugin * feat(open-knowledge): frontmatter schema file picker + agent-surface tests Add a pick-or-create schema-file affordance to the frontmatter mapping editor: a folder button that browses existing .ok/schemas/*.json and a file-plus button that scaffolds a new draft-07 schema by name. Backed by a new GET /api/lint/frontmatter-schemas listing endpoint and a create-empty branch on the existing schema-write endpoint (a field-less request scaffolds the skeleton, idempotent, escape-guarded). core: FrontmatterSchemasListSuccessSchema; the write-request schema now accepts a field-less create-empty request (field/constraint refined as a both-or-neither pair). server: listProjectSchemaFiles + handleFrontmatterSchemasList (GET, read only); createEmptyFrontmatterSchemaFile reusing the existing escape-guard and atomic-write path; the write handler branches edit vs create-empty. app: FrontmatterSchemaFilePicker (Command-in-Popover, two peer buttons) wired into the mapping draft and existing rows; list/create client helpers and a live schema-files hook on the lint-config client. tests: HTTP integration for the write (per-field and create-empty) and list endpoints against a real server; an exec composition test proving schemas_applicable read-time enrichment flows config to the agent response; unit coverage for create-empty and listing; picker DOM tests. Registers the new GET handler as read-only in the attribution + conflict-gate meta-tests. * feat(open-knowledge): offer schema-file deletion when removing a tool-managed mapping Removing a frontmatter mapping whose schema file lives in .ok/schemas (created in the tool) now asks whether to also delete the file. Files mapped from elsewhere in the project only ever lose the mapping. Server: delete branch on the schema write endpoint, scoped to flat .ok/schemas paths, idempotent, unlinks the directory entry so a planted symlink cannot reach outside. New CC1 lint-config derived-view channel signals when the persisted project config or a schema file changes on disk, closing the stale-problems race with the config persistence debounce. Schema create/delete also signals the files channel so show-OK trees update without a reload. App: confirm dialog on the mapping row, delete client helper, and the problems banner now hides entries for files no live mapping references so the stale compose never flashes. * feat(open-knowledge): schema field delete, rename, description, enum type Close the parity gaps with the agents-manage-ui schema builder while keeping the non-destructive merge posture: every operation is a surgical edit and unmodeled keywords survive verbatim. Core: removeSchemaField and renameSchemaField (rename carries the full property object, required membership, and key position; refuses missing source or existing target), description joins the modeled constraint keywords, and the write request schema gains removeField and renameTo shapes with mutual-exclusion refinements. Server: remove and rename wrappers over a shared guarded transform spine (existing file required, escape-guarded, atomic write); handler branches on the new shapes. App: field rows get an editable name (commit-on-blur rename), a remove button, and a description input; the type select adds an enum pseudo-type for discoverability that maps to the standard enum constraint on disk. * feat(open-knowledge): Source/Fields toggle for opened schema files Opening a tool-managed frontmatter schema (.ok/schemas/*.json) in the editor now dispatches to a dedicated SchemaConfigEditor with the same segmented Source/Fields toggle the markdownlint config editor ships: Source is the raw read-only file, Fields mounts the per-field schema editor from Settings directly over the file. Fields is gated to files a live frontmatter mapping references (the field editor reads the resolved schema from the effective config); unmapped schemas keep Source with an explanatory disabled segment. Shares the lint-config view-mode preference so one choice governs both config surfaces. * feat(open-knowledge): nested schema field editing via parentPath Address fields inside object-typed properties end to end: the core edit operations (constraint merge, remove, rename) take a parentPath of object-property segments (an array on the wire, not a dotted string, since frontmatter keys may contain dots), navigating with create-on-write for adds and typed refusals for missing or non-object segments. Required membership toggles on the addressed parent, matching JSON Schema's per-object required semantics. The field editor recurses into object rows (bounded depth) with an add-field affordance per level, and every row operation carries its path. HTTP request schema caps parentPath at 8 segments and requires it to accompany a field operation. * feat(open-knowledge): typed array elements + type icons in the schema editor Array fields get an element-type select (string, number, boolean, enum, object) writing items.type through the same non-destructive merge, and array-of-object elements render as editable nested rows: parentPath gains an {items: true} segment that descends into an array field's items sub-schema, so element fields support the full operation set (add, constraint edits, rename, remove, per-element required). No array-of-array UI on purpose; unmodeled items keywords keep the preserved flag. Both type selects now carry per-type colored icons, matching the agents-manage-ui builder affordance. * feat(open-knowledge): denser schema field rows Flatten each field card's header to one scan line, matching the agents-manage-ui builder's density without adopting its persistence: leading colored type icon, mono name input, inline description, required switch, and remove button share a row; type and pattern keep the second line. Commit-on-blur write semantics unchanged. * feat(open-knowledge): schema editor surface for *.schema.json anywhere Widen the Source/Fields dispatch from tool-managed .ok/schemas paths to any file following the ecosystem *.schema.json naming convention, plus the existing .ok/schemas/*.json scope. Mappings already accept schema files anywhere in the project and the per-field write endpoint already edits any in-project path, so the editor surface was the one place still bound to the delete-flow's safety scope. Fields stays gated on a live mapping; a bare dotfile named .schema.json and unconventionally named json stay on the asset preview. * feat(open-knowledge): surface root-level advanced schema rules in Fields view Per-field preserved flags cannot cover keywords that belong to no field: a schema's if/then, dependencies, or additionalProperties were invisible in the Fields view even though they validate and gate edits. The editor now leads with a note naming the root-level keywords it does not model, pointing at the schema file for the full picture. * feat(open-knowledge): schema browser settings panel Rework the frontmatter plugin settings from mapping rows + file picker to a browser over every schema file in the project, mirroring the markdownlint rule browser UX: each discovered schema (project-wide *.schema.json plus .ok/schemas/*.json plus anything config.yml maps) is a toggleable row with a Modified badge, reset-to-default, search, and a New schema button top right. Toggling on writes an enabled: true mapping whose appliesTo pills edit inline below the row; off keeps the mapping with enabled: false; reset wipes it. Clicking a schema opens the file itself in the editor via hash nav — field editing lives on the file surface now, so the settings-embedded field editor, the mapping file picker, and the remove-mapping dialog are gone. Core: mappings gain an optional enabled flag (absent = on); the lint plugin and the agent-surface enrichment skip disabled entries while resolution still inlines their content for the editor, and disabled mappings stay silent on the problems channel. Server: the schemas list endpoint unions the .ok/schemas scan with a filtered content walk for the *.schema.json convention. * feat(open-knowledge): schema browser polish — delete, layout, only-modified Each schema row gains a trash affordance behind a confirmation dialog that deletes the file and wipes its mapping in one gesture; the server delete scope widens from .ok/schemas to the browser's own predicate (*.schema.json anywhere plus .ok/schemas/*.json) so the visible and deletable scopes agree, with the entry-unlink and realpath guards unchanged. The New schema button moves out of the header to sit right of the search bar, alongside a markdownlint-style Only modified filter. * feat(open-knowledge): plain-language appliesTo summaries Each enabled schema row now reads its globs back in words under the pills: a core classifier maps authored patterns onto nameable shapes (every doc, everything under a folder, docs directly in a folder, a single doc, any doc named X, with one plain brace set expanded) split into includes and excludes, and the panel renders the localized sentence. Anything the classifier can't confidently describe falls back to naming the raw glob, so the summary never claims more than the matcher does. Classification mirrors compileAppliesTo's real semantics: picomatch over content-relative, extension-less doc paths. * fix(open-knowledge): honest appliesTo summaries + suspicious-glob warnings Fix the two summary defects: trailing/leading-slash patterns and globs that fail to compile now classify as non-matching (the sentence says nothing can match instead of claiming a doc), and interior-** subtree patterns get nameable shapes (blogs/**/pizza/** reads as everything under pizza/ folders inside blogs/; **/pizza/** as everything under any pizza/ folder). Validation: compileAppliesTo now reports suspicious patterns alongside invalid ones — syntactically fine globs that can never match a doc path (trailing or leading slash) or that target a doc extension (paths are extension-less). The schema resolver surfaces them as advisory config problems, silenced for disabled mappings, and the settings panel admits them to the problems banner. * refactor(open-knowledge): dedupe frontmatter schema selection and write guards Extract selectApplicableFrontmatterSchemas into core so the lint plugin and the property panel's enum constraints share one selector. This fixes a real divergence: a toggled-off schema mapping still drove enum selects in the property panel while contributing no diagnostics. Pinned by a new test. Server-side, a shared src/lint/fs-safety.ts now owns the lexical containment check and the traced atomic tmp+rename write that were copy-pasted across the frontmatter loader, the frontmatter schema writer, and the markdownlint writer. The schema write surface's triplicated escape-guard flow collapses into one resolveSchemaWriteTarget resolver, and basename() replaces the platform-dependent split('/').pop(). App-side, the five near-identical frontmatter-schema POST wrappers collapse onto one helper; delete/create now validate the 200 response like their siblings. Net -121 lines, behavior-identical except the panel fix. * docs(open-knowledge): frontmatter schemas page + two-linter language pass Add advanced/content-rules/frontmatter.mdx mirroring the markdownlint page: schema mappings and appliesTo semantics, draft-07 schema files and the config problems channel, diagnostic anchoring, the settings editor, the Source/Fields schema editor, property-panel enum selects, and the schemas advertisement agents see on reads. Update the surrounding language now that content rules has two linters: the overview no longer says markdownlint is the only linter, both linter pages cross-link, the MCP reference's lint row covers frontmatter validation and the config-problems warnings channel, and the configuration reference gains the contentRules.frontmatter rows. Also fix the markdownlint row's key path, which documented a contentRules.plugins.* nesting that never existed. * docs(open-knowledge): show real lint and fix output on every API surface Captured from actual runs against a scratch project (built CLI, real server, real MCP stdio session), not hand-written: the ok lint text report, the --json shape (0-based LSP ranges, fixes on auto-fixable findings, config-problem warnings, counts), the --fix report, the MCP lint tool's single-doc text and fix: true summaries, the agent write response's lint-violation advisories, and the exec listing's schemas: advertisement. Overview carries the shared shapes (CLI + MCP + write advisories); each linter page shows its own finding: markdownlint with the fixes payload the Fix action applies, frontmatter with anchoring, the got-value enum message, and the config-channel line for a broken schema. The MCP reference lint row links to the examples. * feat(open-knowledge): schema settings and problems-panel discovery polish Review feedback on the frontmatter data-contract work: - The appliesTo pill input names its grammar ("Add file or folder pattern, e.g. guides/**/*") instead of the generic "Add tag"; the field editor's allowed-values inputs say "Add value". - Enabled mappings whose globs match zero docs now warn on the config channel (settings panel + project audit), next to the invalid/suspicious glob warnings. New core helper findZeroMatchAppliesToPatterns; the audit walk is extracted as collectDocFiles so the lint-config surface and the audit agree on what counts as a doc. - Each schema row carries an explicit Edit button beside the name click. - Opening a schema from Settings lands on the WYSIWYG Fields view via a one-shot intent, without flipping the persisted Source/Fields preference. - The Problems panel names the active lint plugins and, with none enabled, replaces the misleading empty state with a pointer to Settings -> Plugins. * feat(open-knowledge): schema row and problems-panel indicator follow-ups - The schema name is plain text now; the Edit button is the row's only way into the file. - The problems panel's plugin indicator collapses to a compact "Checked by N plugins" line whose tooltip names the plugins, instead of an always-visible badge row. * feat(open-knowledge): move Checked-by hint into the Problems header row * feat(open-knowledge): Checked-by hint as a PanelCount pill (matches Graph header) * feat(open-knowledge): Beta tag on the frontmatter schemas plugin settings * feat(open-knowledge): Beta tag on the schema file editor surface * fix(open-knowledge): schema editor Beta tag to the top left * docs(open-knowledge): align content rules docs with shipped contracts Audited the three content-rules pages against the lint and audit CLI commands, the MCP lint tool, and the core lint types. Fixes the places where the docs disagreed with the code, and fills in the contracts that were never written down. Corrections: - appliesTo: a list with no positive glob gains an implicit **, so an exclusion-only list matches everything except the exclusions - write advisories nest under `document`, not at the response root - MCP lint structured content is close to `ok lint --json` but not identical: contentDir vs cwd, fixedCount counts files vs problems, plus the cap fields - the Source/Rules toggle is JSON and JSONC only; YAML and .markdownlintrc open in the read-only preview - YAML configs are re-serialized on edit, which drops their comments - the Problems panel has a Fix all action Newly documented: - `ok audit --json` response shape, with linkTarget on link findings - validation.links, its three values, and where to set it - brokenLinks on write responses, with all three reason values - omittedFileCount and omittedDiagnosticCount - the per-file `fixed` field on `ok lint --json` - advisories for appliesTo globs that compile but cannot match Also corrects the settings path in the markdownlint blog post to Settings > This project > Plugins. * fix: restore 15 skill symlinks deleted by accident The symlinks under .agents/skills/ point into public/agents/plugins/agents/skills/ and are resolved by bare name across agent harnesses, so removing them silently breaks skill resolution repo-wide. They were deleted in afe849caa, a docs commit about presenting a spec as the proposed contract, which has no functional relationship to skill symlinks. That is the signature of an unintended `git add -A`, not an intended retirement. Restored from origin/main. * fix(open-knowledge): silent-correctness fixes from local review Three verified defects in the new frontmatter data-contract paths, plus the docs and changeset corrections that came with them. deleteFrontmatterSchemaFile reported success on ANY parent-dir stat failure. Only ENOENT and ENOTDIR prove the entry is gone; EACCES/EPERM/ELOOP mean we could not prove it, and returning `deleted` there made the GUI drop the mapping and silently stop validating those docs. Those now return a typed refusal. Reachable on macOS via TCC, and via a chmod that removes the search bit on .ok/schemas. resolveFrontmatterSchemas suppressed the broken-schema config warning when a DISABLED mapping loaded the file first: the outcome cached, and a later enabled mapping for the same file skipped the cache-miss branch and never reported. Docs governed by that schema went unvalidated with no operator signal, and the suppression was order-dependent. The report now sits outside the cache-miss guard with a per-file dedup set so two enabled mappings still report once. applyFieldConstraint replaced tuple and boolean `items` with a fresh object holding only the new constraint, destroying the user's positional definition on any array-field edit. Worse than data loss: draft-07 ignores additionalItems once items is a single schema, so a surviving `additionalItems: false` became dead config. The same shape is already refused by navigateToParent, so editing now refuses too, which removes an internal contradiction rather than adding a new posture. Also: correct the ok lint --json example (warningCount said 3 with only 2 diagnostics), note that --errors-only never gates on frontmatter findings, document the exec tool's schemas output in the MCP reference, bump the changeset to minor per the pre-1.0 convention for additive features, and fix an isToolManagedSchemaPath docstring that named the wrong predicate and understated the delete scope. * fix(open-knowledge): review follow-ups on lint diagnostics and a11y Invalid appliesTo globs now carry the engine's own reason. picomatch names the actual defect ("Missing closing: ]"), which was being discarded, leaving the user with a message that said a glob was invalid but not why. invalidPatterns becomes {pattern, detail} to carry it, mirroring the suspiciousPatterns shape already in that interface. listProjectSchemaFiles logged nothing when the directory could not be read, so an EACCES under macOS TCC produced an empty schema picker indistinguishable from a first run. ENOENT and ENOTDIR stay quiet; anything else warns. The schema-description input had no accessible name of its own. A placeholder is only a last-resort fallback in the name computation, and every row computed the same one, so the name neither identified the field nor stayed correct once a description existed. Now labelled per field through the t macro, matching the three sibling interpolated labels in the same component. Catalogs re-extracted. Collapse the third copy of isInside onto the fs-safety primitive this branch introduced, and correct two docstrings that understated the delete surface: it admits any *.schema.json in the project, not only tool-managed .ok/schemas/ paths. Documents why write scope is deliberately broader than delete scope rather than narrowing it, since a mapping may point at any project-relative JSON the linter can already read. * test(open-knowledge): pin the order-dependent suppression and enum multi-ness The frontmatter-schemas fix landed without a test for the scenario it fixes. The existing suite covered a single disabled mapping staying silent, but not the duplicate-file ordering that was the actual bug, so the fix was one refactor away from silently regressing. Adds the disabled-then-enabled case, the two-enabled no-double-report case, and the disabled-only silence case. Mutation-checked: reintroducing the report inside the cache-miss branch fails the first test and only that one. Also covers the existing multi-ness mismatch fallback in the property panel, where a scalar enum and an array items.enum govern one field. Vocabularies in that test are identical so only the multi-ness guard can cause the drop, and both orderings are asserted since neither schema may decide the shape. * fix(ok-marketing): declare core's new ajv, ajv-formats and picomatch deps The vendored @inkeep/open-knowledge-core dist is derived from packages/core at build time, but the vendored package.json is committed and is what tells pnpm which runtime deps to install. The frontmatter schema feature added ajv, ajv-formats and picomatch to core, so the derived dist imports them while the manifest never declared them, and the Vercel build failed on the first one it could not resolve. Only ajv-formats surfaced in the log because the build stops at the first unresolvable import; the other two were latent behind it. * chore: lock the vendored core's new ajv, ajv-formats and picomatch deps * fix(open-knowledge): drop four unnecessary exports flagged by knip All four symbols are used, but only inside their own module, so exporting them added public surface with no consumer. knip fails the lint job on unused exports; this branch never ran it until the PR existed, which is why four accumulated at once. listFrontmatterSchemas is called twice in its own file; the three applies-to types are referenced only by the exported CompiledAppliesTo interface, which does not require them to be exported to remain usable. * perf(open-knowledge): lazy-load the two config-file editors EditorArea imported LintConfigEditor and SchemaConfigEditor statically, so both shipped in the main chunk for every session even though they render only when a .markdownlint.* or *.schema.json file is opened. That put the main app bundle 5.49 kB over its size-limit budget. Both now load through React.lazy behind a Suspense fallback, matching the pattern already used in this file for LazyActivityModeContent and in DocPanel for LazyGraphPanel. Main bundle drops 490.49 kB to 480.13 kB, back under the 485 kB budget. The two dispatch tests that assert routing to these editors now await the dynamic import. Only the first assertion against each lazy component needs it — later tests in the file find the module already resolved — so the await is on those two and the comment says why. * chore(open-knowledge): raise the all-JS size budget for frontmatter schemas The feature ships a JSON Schema validator plus two editor surfaces, so total JS grows. Splitting cannot offset a total-size budget, and this one was already over before the config editors moved behind React.lazy. 3.55 -> 3.6 MB (actual 3.57). The main-chunk budget stays at 485 kB, which the lazy-load brought back under, so initial load is unchanged for sessions that never open a config file. Matches how every recent feature has tracked this budget: the markdownlint Source/Rules toggle, Mermaid WYSIWYG, the Cmd+K palette, ACP agent threads and the in-app feedback form each raised it alongside their change. * chore(open-knowledge): refresh the ng-anchors catalog after the main merge The catalog is a code-as-truth provenance record whose counts track the real source tree. Merging origin/main added files (production 101 to 104, test 215 to 216) without regenerating it, so the freshness test that deep-equals the committed catalog against a fresh build failed. Regenerated via enumerate-ng-anchors; only the counts and generatedAt move. * fix(open-knowledge): make the enum free-text drop terminal enumConstraintsForDoc dropped a field to free text when two schemas disagreed, but the drop was not sticky: a third schema hit the "no existing constraint" branch and re-added its own vocabulary. With A offering [x,y], B mismatching on multi-ness, and C offering [z], the property panel ended up offering [z] — a value A forbids — and which schema won depended on entry order. That contradicts the module's contract that an offered value satisfies every governing schema. Reachable because schema selection dedups by file key, so distinct files with overlapping appliesTo all govern one doc. Blast radius was the panel only; validateFrontmatterSource always warned independently against every schema. But the panel could steer a user toward a value it had implied was safe. Conflicted fields are now tracked and skipped on later schemas, so the result is order-independent across the whole schema set rather than just pairwise. Both terminal paths (multi-ness mismatch and empty intersection) are covered by tests that fail against the previous behaviour. * fix(open-knowledge): stop the schema listing from re-admitting .ok The frontmatter schema-file listing walked the content tree with the .ok re-admission flag set, which lifts ContentFilter's always-skip floor. That made the listing a second surface able to enumerate OK's internal state, and the showok-caller-coverage gate exists to catch exactly that: the flag is pinned to the tree-listing reveal, and a new consumer is meant to be a deliberate decision rather than a new call site. The re-admission was for consistency with the Show All Files tree, not necessity. The handler's first discovery source already scans .ok/schemas/ directly, so the walk only needs to find the ecosystem *.schema.json convention in ordinary project directories. Dropping it narrows the capability back to the one sanctioned surface; the only discovery lost is a *.schema.json living under .ok/ but outside .ok/schemas/, which the tool never creates. Introduced by f51ef5992 and unnoticed because CI had not run on this branch until the PR existed. 48 integration and meta tests pass, including the frontmatter listing over HTTP. * fix(open-knowledge): converge other windows on a markdownlint rule write handleWriteFrontmatterSchema signals the lint-config CC1 channel after a successful write; its markdownlint sibling never did, so toggling a rule in one window left every other window linting against a stale config until it happened to refetch. This PR is what establishes lint-config as the channel for config convergence, so the sibling write surface belongs with it. Also closes two coverage gaps in code this PR added: a disabled mapping must not reach agents through schemas_applicable, and three schemas must narrow to the running intersection rather than folding against the original values. * docs(open-knowledge): cross-reference the two appliesTo selection sites schemasApplicableToDoc applies the same skip-disabled / match / dedup triad as selectApplicableFrontmatterSchemas, but over persisted mappings rather than resolved entries, because enrichment advertises which files govern a doc without loading them. Nothing links the two, so a change to what governs could land in one and silently miss the other — and only the core one is covered by the validator's tests. GitOrigin-RevId: 86e58ac35b8767d82165ef210136d56d63e165a3
|
|
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.
Copybara-translated 1 Inkeep OSS change. Rebase-merge this PR so the prepared commit lands directly on public main.