Repository navigation
feat: comments - #7
Merged
Merged
Conversation
Philipinho
commented
Nov 9, 2023
Member
- create comment
- reply to comment thread
- edit comment
- delete comment
- resolve comment
* create comment * reply to comment thread * edit comment * delete comment * resolve comment
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jun 24, 2026
…most) Adds floatLeft / floatRight image alignment so text wraps beside the image, beyond the existing block left/center/right. Ported from Forkmost PR docmost#7 / upstream Docmost PR docmost#1132 (fuscodev), adapted to gitmost's imperative image node-view (the upstream uses a React styled component; ours styles the node-view container directly via applyAlignment). - editor-ext image.ts: `setImageAlign` accepts `floatLeft`/`floatRight`; `applyAlignment` resets float/padding then, for a float mode, sets `float:left|right` + side padding on the (shrink-to-fit) container so text flows beside it (the inner <img> already has max-width:100%). The resolved align is mirrored onto the container as `data-image-align` for the responsive rule. `data-align` already round-trips the value through parse/renderHTML, so float survives serialization / collab / history with no schema change. - image-menu.tsx: Float-left / Float-right bubble-menu buttons (IconFloatLeft/ Right) with active state. - image-resize.module.css: on narrow screens (<=600px) a floated image collapses to full width and drops the float (`!important`, keyed on data-image-align) — the upstream "100% width on small screen" follow-up. - i18n: en-US + ru-RU strings. editor-ext build + client tsc --noEmit clean. Visual wrap behavior is best confirmed in-browser (logic/serialization verified by build + types). Co-Authored-By: Claude Opus 4.8 <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jun 25, 2026
docmost#159) The only test command in CI was `pnpm -r test` (unit `.spec.ts` on mocks). `test:int` (`.int-spec.ts`, real Postgres/Redis) ran nowhere in CI — there were no DB `services:` — so the cost-cap, FK-cascade, jsonb round-trip and real AI-apply integration tests never gated a PR, and regressions in those high-severity paths stayed green (red-team finding docmost#7). Add `services: postgres (pgvector) + redis` and a `pnpm --filter server test:int` step. The pgvector image is required because migrations create vector columns and global-setup runs `CREATE EXTENSION vector`. Service credentials/db match the defaults in apps/server/test/integration (docmost / docmost_dev_pw, maintenance db `docmost`, redis 6379), so no TEST_*_URL overrides are needed; global-setup drops/recreates the isolated docmost_test DB and migrates it. NOTE: the workflow change itself can only be validated by an actual CI run (YAML parses locally); the int-spec suite is verified passing locally on this branch. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jun 26, 2026
…rrent A<->B cycles (docmost#207) The server-side move cycle guard (getPageBreadCrumbs) and the move UPDATE ran as two separate, unlocked statements. Two concurrent moves ("A under B" and "B under A") could each read the same pre-write acyclic snapshot, both pass the guard, then persist A.parentPageId=B AND B.parentPageId=A — a parent/child cycle (TOCTOU, docmost#207 docmost#7). Run the cycle check and the UPDATE inside one transaction (executeTx) guarded by a per-space advisory lock (pg_advisory_xact_lock, held until COMMIT) so all moves within a space serialize: the second mover blocks until the first commits and then sees the freshly written parent, so its guard rejects the cycle. getPageBreadCrumbs gains an optional trx so the check runs on the locked snapshot. Adds an integration test driving two opposing concurrent movePage calls and asserting no cycle ever persists and exactly one move is rejected. Updates the movePage unit-test stubs for the new transactional path. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jun 26, 2026
…cmost#207) getPageBreadCrumbs (ancestor CTE) and forceDelete (descendant CTE) used withRecursive + unionAll with no CYCLE clause or depth cap. If a parent/child cycle already exists in the data (e.g. one slipped in via the docmost#7 TOCTOU race), both queries loop forever — hang / statement timeout. Worse, the move guard itself runs the ancestor CTE, so a cycle would disable the very guard meant to prevent it (docmost#207 docmost#8). Add a depth counter bounded by MAX_PAGE_TREE_DEPTH to both recursive CTEs; the walk stops at the cap, so a cycle yields a bounded result instead of hanging. Real page trees are only a few levels deep, so the cap never truncates a legitimate result. getPageBreadCrumbs selects an explicit column list (not selectAll) so the internal depth counter never leaks into the breadcrumb shape. Adds an integration test that seeds an A<->B cycle directly and asserts both getPageBreadCrumbs and forceDelete return bounded / complete under a short connection-level statement_timeout instead of hanging. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 4, 2026
…ost#293 canon docmost#7) A `highlight` mark WITHOUT a color now serializes as the Obsidian/GFM `==text==` syntax (closing hand-authoring gap A19); a highlight WITH a color keeps the `<mark style="background-color: …">` HTML form (condition is deterministic on the color attr). On the raw-HTML path (columns/spanned cells) BOTH forms stay `<mark>` via inlineToHtml — markdown is not re-parsed inside a raw-HTML block. Parse: `==` is not standard markdown, so the importer uses a DEDICATED marked instance (`new Marked().use({extensions:[highlightMark]})`) rather than the global singleton — registered once, never leaks `==` behavior to other callers. The inline extension tokenizes `==text==` (non-empty, non-space-leading inner, lazy so `==a== ==b==` is two marks; inner re-tokenized so nested marks survive; `====`/`==x` fail-open to literal) into `<mark>` with no color, which the schema parses as a color-less highlight. Inline code (`` `a == b` ``) stays code via marked token precedence. marked 17 defaults (gfm:true, breaks:false) are identical for the fresh instance, so tables/strike/autolinks are unaffected. Losslessness: a LITERAL `==` in a text run would otherwise be misparsed as a highlight on the next import, so `case "text"` backslash-escapes each `=` of a `==` pair (marked decodes `\=` back to `=`), and this round-trips byte-stably. The escape does NOT run for inline-code runs, and — CRITICALLY — codeBlock now reads its child text RAW (schema `content: "text*"`) instead of routing through `case "text"`: marked does not decode `\=` inside a fence, so escaping there would permanently stamp backslashes into any `==` comparison (ubiquitous in source code) and corrupt the block on the git-sync data path. Tests: new highlight.test.ts (19 cases incl. serialize forms, colored vs plain, column `<mark>` path, nested marks, inline-code exclusion, literal-`==` escape, fail-open, AND a codeBlock-with-`==` regression proving no backslash corruption + byte-stable round-trip). Golden inline-mark matrix flipped top-level no-color highlight to `==m==`; the kept `<mark style=…>` assertions are the colored/ raw-HTML cases. package vitest: 559 passed; tsc clean. git-sync: 268 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 4, 2026
…cmost#6) mathInline serializes as `$LaTeX$` and mathBlock as an own-line `$$\n<latex>\n$$` fence (multi-line safe), closing hand-authoring gap A18. The LaTeX still lives in node.attrs.text; a literal `$` inside it is escaped `\$`. On the raw-HTML path (columns/cells) math keeps the schema-HTML `<span data-type="mathInline">` / `<div data-type="mathBlock">` form (markdown is not re-parsed inside raw HTML) — blockToHtml gets an explicit mathBlock case and inlineToHtml a mathInline case, sharing the mathInlineHtml/mathBlockHtml helpers with the fallbacks so the two forms cannot drift. Parse: mathInlineExtension (inline) + mathBlockExtension (block) are added to the SAME dedicated marked instance introduced for canon docmost#7 (global singleton untouched). The inline extension uses a currency-safe PANDOC rule: an opening `$` must not be followed by whitespace, and the closing `$` must not be preceded by whitespace nor followed by a digit — so `$5`, `$5 and $10`, `a $5 b $6 c`, `100$` stay literal text while `$x^2$` is math. The block extension matches a `$$` fence line and captures multi-line LaTeX non-greedily up to the next `$$` line. The pandoc boundary rule lives ONCE in the new math-inline.ts (INLINE_MATH_SOURCE) and is shared by the import tokenizer (^-anchored) and the export prose escaper (global), so parse and serialize cannot disagree about what is math. escapeProseMath (case "text", non-code runs only) escapes ONLY the two delimiting `$` of a span the rule WOULD match, so a would-be-math prose span like `the set $A$` re-imports as literal text while currency `$5 and $10` is emitted CLEAN (zero backslash churn). marked decodes `\$`→`$` on re-parse, byte-stable. Fallbacks to the lossless schema-HTML form (all documented + tested): mathInline → <span> when empty / whitespace-edged / multi-line / pre-existing `\$` / trailing `\` / immediately before a digit-text sibling (renderInlineChildren guard, so `$…$5` can't lose the node); mathBlock → <div> when the LaTeX contains `$$`. Each fallback round-trips losslessly and byte-stably. Code safety (guards the canon docmost#7 regression class): codeBlock reads raw child text and inline `code` runs are excluded from escapeProseMath, so `$5`/`$x$` in code stay literal with no math and no backslash corruption. ReDoS-checked on adversarial 40k-char inputs (0–1 ms). Tests: new math.test.ts (26 cases: serialize exactness, multi-line block, `\$` escaping, currency ×5 asserting no `\$`, prose escape, columns schema-HTML, inline-code/codeBlock safety, fail-open). Goldens in roundtrip / markdown-converter flipped top-level math to `$…$`/`$$…$$`; the escapeAttr-idempotence golden wraps math in a column (still exercises escapeAttr); columns/raw-HTML math assertions unchanged. package vitest: 585 passed; tsc clean. git-sync: 268 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 4, 2026
… ^ in link/alt text (docmost#333 review F5) F1 (round 1) wrapped the image alt in escapeLinkText, and that helper also guards the link-form media captions (attachment/pdf/embed). But its character class covered only stock CommonMark — NOT the Docmost inline EXTENSIONS this same PR registers on the marked instance: highlight `==x==` (canon docmost#7), math `$x$` (canon docmost#6), footnote `^[x]` (canon #2). Their triggers `= $ ^` are not CommonMark punctuation, so an alt or media filename like `x $A$ y`, `use ==bold==`, `^[fn]`, or `data $A$.csv` was silently turned into a math/highlight/footnote node on import — the same class of round-trip data loss F1 closed, reintroduced by this PR's own canon. Fix: add `= $ ^` to the escapeLinkText class (`/[\\`*_~[\]<&!()=$^]/g`). `\= \$ \^` decode back to literals (all ASCII punctuation) AND, being escape tokens, stop the extension tokenizer from matching — verified lossless byte-stable round-trip. Updated the helper comment to name the two trigger sets (CommonMark + Docmost inline extensions). Extended the adversarial round-trip tests: image alt gains `x $A$ y` / `5$ and 10$` / `use ==bold==` / `^[fn]` / `cost $5 == price`; pdf name gains `data $A$.csv` / `q3 ==final==.pdf` / `5$ and 10$.pdf` / `note ^[x].pdf` — all byte-stable with the node intact, so the hole can't reopen. package vitest: 658 passed; tsc clean. git-sync: 268. mcp: 454. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 12, 2026
Эскалация (владелец) — Опция A: 100k только фолбэк для НЕсконфигурированных инсталляций; при заданном chatContextWindow бюджет = floor(0.7×window) БЕЗ капа (бюджетер — защита от брика об контекст-окно, не эконом-лимитер). Спек репиннут resolveReplayBudget(1_000_000)→700_000. DO1: агрессивный next-turn recovery ×0.5 вынесен в чистую resolveEffectiveReplayThreshold + тест линковки replayOverflow→0.5×бюджет (mutation-verified). DO2: checkNewComments partial-failure — per-page reject скипается (→null), скан резолвится, порядок выживших сохранён; тест docmost#7 (mutation-verified). DO3: ai-chat.write-volume.spec.ts → .int-spec.ts (WAL-гард не бежал НИ в одном CI-lane) + маппер @docmost/token-estimate в jest-integration.json; реальный WAL на pg:5432 зелёный (трейс v1 140MB→v2 0.04MB). DO4: CHANGELOG [Unreleased] по docmost#490. Follow-up: issue docmost#520 (эскалация агрессивной доли при незаданном окне + малом реальном контексте). Ребейзнут на develop (волна 1 смержена): только 6 коммитов docmost#490 над develop. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 17, 2026
…rf flake Two failures surfaced after the round-1 e2e baseHash fix unblocked the mcp e2e: - editor-ext table schema: TableCell/TableHeader did not declare an `align` attribute, so the docmost#647/docmost#672 server-side guarded-replace write path (jsonToNode -> Node.fromJSON(getSchema(editor-ext exts))) stripped GFM column alignment on persist — the old client-side collab write went through the converter schema (which HAS align), masking the drift. Mirror the converter's docmost-schema align onto editor-ext so the authoritative editor/collab schema preserves it (round-trips |:--|:-:|--:|). Invariants docmost#7/docmost#4. - drawio-layout benchmark (docmost#486): the `dt < 5000` sanity bound compared TOTAL round-trip time (worker startup + elkjs load + IPC + the internal 5000ms ELK budget) against the internal budget, flaking on loaded CI runners. Loosen to 10000ms; the event-loop-responsive / layout-applied guarantees are unchanged. Verified: editor-ext + prosemirror-markdown build; converter tests green (895); runtime proof that Node.fromJSON now preserves tableCell/tableHeader align; drawio-layout perf test green locally. Follow-up: add a CI parity check for node-attribute drift between editor-ext and prosemirror-markdown/docmost-schema (the gap that let `align` diverge).
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 20, 2026
…d the pm-markdown mirror (docmost#684) Invariant docmost#7 says no hand-synced mirrors: the Tiptap node schema lives in packages/editor-ext (authoritative; collab builds getSchema(tiptapExtensions)) AND packages/prosemirror-markdown/docmost-schema.ts (the PM<->MD converter). The existing schema-surface-snapshot.test is a LOUD MANUAL review gate, and the docmost#493 contract test is asymmetric (editor-ext -> mirror only) — so attribute drift in the OTHER direction wasn't caught. Real incident: `align` on tableCell/tableHeader was declared in the mirror but missing from editor-ext, so after the write path moved to server guarded-replace (docmost#647/docmost#672), Node.fromJSON(getSchema(editor-ext)) STRIPPED align -> GFM table alignment silently lost on persist. (The align fix itself already landed on develop; this adds the missing automatic guard.) New apps/server/src/collaboration/schema-attr-parity.spec.ts builds BOTH schemas and diffs the attribute-NAME set of every shared node/mark in BOTH directions, failing with the exact node+attr+direction (e.g. "tableCell.align: in mirror but MISSING in editor-ext (write path STRIPS it)"). A documented per-attr ACCEPTED_DIVERGENCE allowlist covers the 4 intentional structural divergences (highlight.colorName, image.title, youtube.align, youtube.start) — each with the side + reason; a NEW drift is never pre-blessed, so an align-class regression still reddens. Plus a stale-allowlist test (entries can't rot) and a vacuity guard (>20 shared types). Lives in the server package — the only place that can import the real write-path tiptapExtensions without a third copy of the list. Verified: schema-attr-parity 4 passed; mirror snapshot + docmost#493 contract 6 passed; align round-trip 34 passed. Non-vacuous: removing align from editor-ext reddens the parity test with the exact strip message. CI runs server specs via pnpm -r test, so it's gated with no workflow change. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 20, 2026
…ll-switch (docmost#686 phase 2) PR A, phase 2. Adds the per-user CRUD surface a member uses to manage their OWN external MCP servers (persisted by phase 1). Nothing consumes personal servers at run time yet — the agent-side union + per-user cache invalidation are PR B. - account-mcp-servers.controller.ts: @controller('account/mcp-servers'), JwtAuthGuard, NO CASL admin gate (a normal member manages their own). Routes mirror the admin controller (list/create/update/delete/test). assertEnabled() runs FIRST in every handler -> 403 when MCP_PERSONAL_SERVERS_ENABLED=false, so a disabled feature never reaches the service. Every handler passes the authenticated @authuser().id + @AuthWorkspace().id — no client-supplied user id. - account-mcp-servers.service.ts: reads/writes go ONLY through phase-1 *ForUser repo methods (owner-scoped; a non-owner id -> 404). createPersonal in one tx: lockUserRow (FOR NO KEY UPDATE on the users row) -> countByUser -> >= max -> BadRequest -> insert, so a parallel burst can't exceed the limit. SSRF assertMcpUrlAllowed on create + url-change. - mcp-server-view.util.ts: single shared definition of the write-only-headers projection (toMcpServerView -> hasHeaders bool, never headersEnc) + encrypt + url-allow, consumed by BOTH admin and personal paths (AGENTS docmost#7 — no hand-synced mirror of the header-leak guard). Admin service delegates to it, no behaviour change. - workspace.controller entitlements now returns mcpPersonalServersEnabled (bool) for PR C's UI to gate the page. McpServerIdDto -> @IsUUID (a non-uuid id now 400, not a Postgres-22P02 500; benefits admin too). Verified (internal adversarial review + real Postgres): no cross-user / admin<-> personal access; headers never leak in any response or log; kill-switch on every route (neuter-proven); limit atomic (burst-of-4 with MAX=2 -> exactly 2 on real PG); SSRF enforced. Controller unit 10/10, integration 22/22 (service 6 + repo 16), tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 20, 2026
Add the account-level page to manage personal external MCP servers, mirroring the account API-keys page. Extract the reusable row/form/modal wiring into a single shared module (features/ai-mcp) consumed by both the admin and the account pages, so the two never diverge (AGENTS invariant docmost#7). - shared features/ai-mcp: canonical types + injectable create/update/test hook contract + AiMcpServerRow + McpServerFormModal + form + moved test-view/form-utils helpers (with their specs) - admin ai-mcp-servers.tsx refactored to consume the shared row/modal; no admin behaviour change (same guard, fields, validation, confirms) - new account page + scoped service (/account/mcp-servers*) + query key ["account-mcp-servers"], distinct from the admin cache - kill-switch gating via the workspace entitlements mcpPersonalServersEnabled flag: friendly disabled Alert (not a raw 403), list fetch gated off, sidebar item hidden when off; fail-safe to hidden when the flag is absent - routing: APP_ROUTE.SETTINGS.ACCOUNT.MCP_SERVERS + lazy route + sidebar item
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 20, 2026
…fig keys were dead in dev (docmost#638) docmost#638's finding #1 (LOCAL_FIRST_ENABLED unreachable in dev) is already fixed on develop by 62994e1 (docmost#639), and a guard test existed. But docmost#639's guard carried a hardcoded 4-key list — itself the hand-synced mirror invariant docmost#7 forbids — so diffing the getConfigValue call sites against the vite allowlist found the same defect still live for three more keys, permanently undefined in dev: - OFFLINE_GRACE, which silently fell back to its 30d default, so docmost#640's session boundary could not be exercised in dev at all; - DRAWIO_RASTER_ENABLED (docmost#629) and EXCALIDRAW_RASTER_ENABLED (docmost#632), which read as OFF in dev whatever .env said. All three are mirrored into window.CONFIG by static.module.ts, so prod honoured them — a dev-only divergence, exactly the original bug class. Fixed by generation rather than another guard: a dependency-free apps/client/src/lib/client-config-keys.ts exports CLIENT_CONFIG_KEYS (17 keys) and buildDefineEnv(env), and vite.config.ts now does `"process.env": buildDefineEnv(env)`. The destructuring block and the hand-listed define object are both gone — three copies collapse into one (-105/+13). Generation is clean here because the module has no imports, so Node can evaluate it during config load and vitest can import it without the plugin graph. It stays an explicit allowlist rather than a passthrough on purpose: loadEnv(mode, dir, "") returns the FULL server env, so passing it through would inline DATABASE_URL/APP_SECRET into a public bundle. A regression test pins that. The remaining one-hop mirror (the list vs the getConfigValue call sites) is covered by a derivation test that extracts the keys from config.ts. The superseded flag-reachability.test.ts is deleted: its two guarantees are strictly subsumed, since the new test covers every key through the real generator and a key missing from either former site now surfaces identically. Behaviour: prod is untouched (getConfigValue takes the window.CONFIG branch there, so the process.env branch is dead code), and the three added keys are non-secret operator flags already published to every prod browser via window.CONFIG. LOCAL_FIRST_ENABLED still defaults to false — this makes keys reachable, not enabled — with a test pinning all four defaults. Both guards are neuter-proven: dropping the flag entries from CLIENT_CONFIG_KEYS reddens the observable-property test exactly as the pre-fix bug behaved ("expected undefined to be 'true'"), and hand-listing the define object reddens the generation test. Scope: this is docmost#638's finding #1 only. Phases 3-7 of the local-first/offline program are not touched. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Aug 2, 2026
…ntic search (docmost#696) The picker exposed 112 curated icons of 1995; the rest were reachable only by English substring search (≤120 hits). Now the whole catalog (1746 canonical icons) is browsable, virtualized, and searchable by meaning (tags, aliases, common Russian words), and the scroll-drifting Mantine name-tooltip is gone. - lucide-catalog.generated.ts: one committed artifact (a .ts wrapper, not .json — a JSON import blows tsc to ~294k types), built by a hand-run generator (apps/client/scripts/gen-lucide-catalog.mjs; default / --tarball / --offline modes; NOT in CI). The dynamicIconImports parse rule is a single source (scripts/lucide-imports.mjs) shared by the generator and the guard test (AGENTS.md docmost#7). The artifact carries degraded[]; the guard test fails the build on a non-empty degraded not matching the allowlist (AGENTS.md docmost#10). - lucide-icon-grid.tsx: @tanstack/react-virtual grid (explicit measure() so the estimateSize-not-in-deps memo recomputes on model switch), a loading|ready| failed state machine, imperative dynamic import of the catalog (never eager, and a reject can't burn the app-wide reload budget), visible failed+limited mode with Retry. Tooltip removed. The catalog is reachable ONLY via the one dynamic import (image-smoke.sh S5 guards against it entering an eager chunk). - lucide-search.ts: canonicalOf (a stored alias still resolves), tag/alias search, Russian synonyms (ru-icon-synonyms.ts). Curated aliases funnel / circle-question-mark canonicalized. - i18n: picker strings in en-US (source) + ru-RU. Verified: pnpm --filter client typecheck / build / test all pass (1748 tests, incl. the guard + search suites against the real catalog); generator idempotent and byte-identical across all three network modes; degraded-guard mutation-checked non-vacuous.
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Aug 2, 2026
…ost#681) editor_tx_ms only measures the synchronous ProseMirror transaction and is blind to the React re-render/paint that follows a keystroke. Add editor_key_latency_ms = the full keydown->next-paint duration, captured with a PerformanceObserver on the Event Timing entry type. - vitals.ts: a passive PerformanceObserver({type:"event", durationThreshold:16, buffered:false}), wrapped in the same commented try/catch graceful-degrade as the longtask observer (inv docmost#10). A single filter reportEditorKeyLatency() keeps name==="keydown" && live .ProseMirror focus, reporting entry.duration through the existing reportClientMetric sink (self-gated by isVitalsActive). editor_tx_ms is untouched. - client ALLOWED_NAMES + reportClientMetric union + server ALLOWED_METRIC_NAMES: the metric name declared in all three lockstep sites (inv docmost#7), each guarded. - 6 client tests drive the REAL filter through real jsdom focus + a wiring test proving the observer is installed with the right options and connected to the filter (inv docmost#8); 1 server validator test asserts the name is accepted. Closes docmost#681
PMQ9
referenced
this pull request
in cccvu/docmost
Aug 30, 2026
…iction gate, collab guard, PEP↔PDP consumer contract; timeout/chunking bug-exposers (#10/#15) Adds to the fork's authz compatibility suite (Task #16 / Epic #7): - search/pdp-search.completeness.spec.ts — I5 authorized-k-under-truncation (match beyond the first window still returned) - page-restriction/page-restriction.service.spec.ts — only a space-admin may restrict/grant - collab/collab-disconnect.controller.spec.ts — constant-time service-secret guard + fail-safe re-check - contract/pep-pdp-consumer.contract.spec.ts — the consumer half of the PEP↔PDP HTTP contract (#13) - platform-authz.client.contract.spec.ts — INTENTIONALLY-RED bug-exposers: no request timeout (#10), no 1000-cap chunking (#15) All additions live under apps/server/src/authz/ (upstream boundary intact). The two client-contract failures are real defects to fix in #17; they assert intended behavior and are not weakened. Co-Authored-By: Claude Opus 4.8 <[email protected]>
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.