Звіт у форматі JSON машиночитний
{
"data": {
"repo": {
"topics": [
"dashboard",
"declarative",
"dom",
"forms",
"framework",
"frontend",
"no-build",
"proxy",
"reactive",
"table",
"zero-dependency"
],
"is_fork": false,
"size_kb": 580,
"has_wiki": true,
"homepage": "https://qrp.nemanja.top/",
"languages": {
"CSS": 11179,
"HTML": 61215,
"JavaScript": 298103,
"TypeScript": 5735
},
"pushed_at": "2026-07-17T00:27:50Z",
"created_at": "2026-07-14T15:22:49Z",
"owner_type": "User",
"updated_at": "2026-07-17T00:27:54Z",
"description": "A data-first, declarative, low-overhead framework for dashboards. Zero RUNTIME dependencies, zero build step — the devDependencies below are only for tests, lint, and git hooks.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "master",
"license_spdx_raw": "MIT",
"primary_language": "JavaScript",
"significant_languages": [
"JavaScript",
"HTML"
]
},
"owner": {
"blog": "https://nemanja.top/",
"name": "Nemanja Nedeljković",
"type": "User",
"login": "nemanjan00",
"company": "FlockSocial",
"location": "Belgrade, Serbia",
"followers": 117,
"avatar_url": "https://avatars.githubusercontent.com/u/448151?v=4",
"created_at": "2010-10-21T11:30:52Z",
"is_verified": null,
"public_repos": 233,
"account_age_days": 5752
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.7.0",
"kind": "minor",
"published_at": "2026-07-17T00:27:34Z"
},
{
"tag": "v0.6.1",
"kind": "patch",
"published_at": "2026-07-16T22:34:59Z"
},
{
"tag": "v0.6.0",
"kind": "minor",
"published_at": "2026-07-16T10:30:16Z"
},
{
"tag": "v0.5.2",
"kind": "patch",
"published_at": "2026-07-16T09:50:20Z"
},
{
"tag": "v0.5.1",
"kind": "patch",
"published_at": "2026-07-15T19:24:55Z"
},
{
"tag": "v0.5.0",
"kind": "minor",
"published_at": "2026-07-15T18:05:51Z"
},
{
"tag": "v0.4.10",
"kind": "patch",
"published_at": "2026-07-15T18:02:48Z"
},
{
"tag": "v0.4.9",
"kind": "patch",
"published_at": "2026-07-15T14:37:00Z"
},
{
"tag": "v0.4.8",
"kind": "patch",
"published_at": "2026-07-15T10:24:47Z"
},
{
"tag": "v0.4.7",
"kind": "patch",
"published_at": "2026-07-15T09:18:08Z"
},
{
"tag": "v0.4.6",
"kind": "patch",
"published_at": "2026-07-15T08:41:53Z"
},
{
"tag": "v0.4.5",
"kind": "patch",
"published_at": "2026-07-15T08:21:18Z"
},
{
"tag": "v0.4.4",
"kind": "patch",
"published_at": "2026-07-15T08:14:59Z"
},
{
"tag": "v0.4.3",
"kind": "patch",
"published_at": "2026-07-15T08:01:11Z"
},
{
"tag": "v0.4.2",
"kind": "patch",
"published_at": "2026-07-15T01:12:44Z"
},
{
"tag": "v0.4.1",
"kind": "patch",
"published_at": "2026-07-14T23:22:24Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2026-07-14T23:03:13Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2026-07-14T22:36:51Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2026-07-14T20:02:26Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2026-07-14T19:15:41Z"
},
{
"tag": "v0.1.1",
"kind": "patch",
"published_at": "2026-07-14T19:02:49Z"
}
],
"recent_commits": [
{
"oid": "ea7183479bbd1581280f33be6d5428ffd9c323c9",
"body": "Authoring Custom Elements is tangential to 'turn data into a dashboard' — more a\n'no class extends' flex than a dashboard need — so it's out, per do-one-thing-well.\nCore drops ~4.6 -> ~4.4 KB min+gzip. mount()/scoped() cover in-app component\nlifecycles; the ~50 self-contained lines (state+scope+clea\n[…]\n: removed the Custom elements demo section, the qrp-clock demo,\n imports, highlighter keyword, and module-card mention. index.html render-checked.\n\nPer the tag rule, this is the version after v0.6.1.",
"is_bot": false,
"headline": "0.7.0: remove define() (custom-element registration) — BREAKING",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-17T00:27:34Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0c3e1cec0bfc0b0c1fb5c2a4e95830d5ee101014",
"body": "v0.6.0 was tagged/published before commit 53f17ae (SHARP-EDGES callout in\nREADME + API reference, and the API.md regen documenting list()'s onDuplicateKey).\nPer 'anything after a tag is the next version', that's 0.6.1 — moved the\nSHARP-EDGES bullet out of the published 0.6.0 section into a new 0.6.1 section and\nbumped. Docs only; runtime identical to 0.6.0.",
"is_bot": false,
"headline": "0.6.1: SHARP-EDGES callout + onDuplicateKey docs (post-0.6.0-tag work)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-16T22:34:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "53f17ae6ec1d8da796942341b1986475dc102f60",
"body": "…reference\n\nPoint readers (and coding agents reading the shipped docs) at the gotchas doc up\nfront. Added to bin/gen-api.js's preamble so API.md keeps it on regeneration, and\nto the README intro.\n\nAlso fixes a docs regression this surfaced: ListOptions had been inserted between\nlist()'s JSDoc and it\n[…]\nerface and\nDROPPED the entire ### list section (81 -> 80 exports). Moved ListOptions after\nthe function; list is back, onDuplicateKey documented, export set matches (81).\nFolds into unpublished 0.6.0.",
"is_bot": false,
"headline": "docs: 'read SHARP-EDGES before implementing' callout in README + API …",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-16T22:31:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0daa09dd9470160e6bced575ae2604a04a57715d",
"body": "…f-host docs\n\nBuild:\n- dist/ is now a flat per-module minified mirror — dropped esbuild code-splitting,\n so no shared chunk-*.js. Each module minifies in place (same names, no hashes);\n cross-module imports stay relative (table.js -> ./qrp.js) so core is shared not\n inlined, bundlers still tree-s\n[…]\nd sizes; CLAUDE.md build/release notes updated.\n\nAlso fixes CHANGELOG attribution: restored the 0.5.2 (ships-docs) and 0.5.1\n(guard rework) sections that prior version-shuffling had merged/mislabeled.",
"is_bot": false,
"headline": "0.6.0: flat dist (no chunks), list onDuplicateKey, build-optional/sel…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-16T10:30:16Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e508a5684d522c7a03c9f2a5c0add662af0d4951",
"body": "Reviewer called it 'rare and great' — test a qrp component in a plain node --test\nscript under happy-dom, no browser. It follows from the core premise (real DOM,\nno VDOM/hydration/test-renderer) and is how qrp tests itself, but was never\nsurfaced as a selling point. Added a README section with a verified example (a\ntable going 0->3 rows on a state write via @happy-dom/global-registrator). Folds\ninto the unpublished 0.5.3 docs release.",
"is_bot": false,
"headline": "docs: document headless testability as a first-class plus (0.5.3)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-16T10:13:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c9ab49bfde4b0ecebfefca880a8c6a681e6768fd",
"body": "Readers — humans and coding agents reading the shipped docs — were concluding\nfrom 'zero build / no bundler' that qrp CANNOT use a bundler. It always could;\nthe aimfox review confirmed it's a model ESM package under Vite (exports subpaths,\ntree-shaking, .d.ts). Philosophy: it's an MIT lib, use it ho\n[…]\nUDE.md: philosophy now states build-optional explicitly so future edits keep\n the framing.\n\nDocs/metadata only, no runtime change. Ships because README + description + docs\nreach npm only on publish.",
"is_bot": false,
"headline": "0.5.3: reframe messaging as build-OPTIONAL (not build-forbidden)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-16T10:07:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "16f5ba4712576ba356123c19db8f921fa4860682",
"body": "A coding agent (and humans) learn the API from what's in node_modules, so put the\nreference there: added docs/ and CHANGELOG.md to the files allowlist. The full\nAPI reference, getting-started, sharp-edges, and styling guides now travel with\nthe install — offline, no repo visit.\n\n- README doc + CHANG\n[…]\nUDE.md: package-contents note + release checklist updated (docs/ ships now;\n *.html/docs-site.*/examples/ still don't).\n- ~30 KB added to the packed tarball (48.8 -> 78.7 kB); runtime code unchanged.",
"is_bot": false,
"headline": "0.5.2: ship docs/*.md + CHANGELOG in the npm package",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-16T09:50:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4f33dfb9c00a0b6e2f450c8b436e52d9e8d25348",
"body": "…c-page dedup)\n\nThree loose ends from the review round:\n\n1. form() emitted markup (review §5): STYLING.md had the class table but not the\n NESTING — the reviewer's labels 'sat inline until I inspected the DOM'. Added\n the exact skeleton (bare <h3> outside .settings-section; .setting-item is\n l\n[…]\ns. Verified all four render (headings, TOC, derived\n aria-labels, cross-doc links resolve, live search filter) with no console\n errors. Site-only files, not in the npm allowlist — no version bump.",
"is_bot": false,
"headline": "docs+site: close remaining gaps (form() markup, release checklist, do…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T19:37:48Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6cd00211217a587a1421ec67f7c2bfd07ce675d2",
"body": "Patch bump: 0.5.0 (published) shipped the wall-clock runaway guard; the\nre-entrancy-depth rework (79e4179) is a runtime fix, so it needs its own version.\nMoved that CHANGELOG entry to a 0.5.1 section; 0.5.0 stays as published.",
"is_bot": false,
"headline": "0.5.1",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T19:24:55Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "264f773087e4668a0426166e6adfb32f5f3e2e87",
"body": "Re-measured everything for 0.5.0:\n\nSizes (stale, updated): core ~3.9 -> ~4.5 KB min+gzip; whole library ~17 ->\n~20.5 KB; raw source ~12 -> ~16 KB gz. ESP32 blob rebuilt: app JS ~10.9 -> ~12.7\nKB, HTML ~15.4 -> ~17.4 KB, gzipped ~6 -> ~7 KB (react-dom ~45 KB gz is now ~6x,\nwas 7x). Test badge/count 2\n[…]\nmachine; the paint-timed suite landed on the\ndocumented table within normal jitter. Overwriting curated reference numbers with\nnoisier container/Xvfb figures would only make them worse, so they stand.",
"is_bot": false,
"headline": "docs: refresh sizes (benchmarks re-verified, unchanged)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T19:22:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "79e417933ba5c6e35974cf29fa84d7e81cfc8993",
"body": "Re-running the benchmark for the size/perf refresh surfaced a false-positive in\n0.4.10's loop guard: updateOneNs fires one cell's effect ~22,000 times in a tight\nsynchronous loop, and the 1000-runs-per-second rate guard tore it down at 1001.\nA legitimately HOT reactive path (bulk writes, animation, \n[…]\n in practice.\n\n- new test: 5000 sequential updates to one effect never trip the guard\n- existing A<->B runaway + phase:'loop' report still pass\n- d.ts/SHARP-EDGES/CHANGELOG updated; API.md regenerated",
"is_bot": false,
"headline": "fix(core): runaway guard detects re-entrancy depth, not wall-clock rate",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T19:22:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9d8c351a780ba8fbd272cce549306d1db95e9ded",
"body": "Bump for this round's new module + features. 0.4.10 (published) keeps only what\nshipped in it — the runaway-effect guard and the two createHttp fixes. The new\ndatagrid module (a new public subpath) makes this a minor bump; datagrid,\ncollection.filtered(), behaviors scope auto-teardown, query({arrays}), and the\nmarker console.error escalation move under the 0.5.0 heading.",
"is_bot": false,
"headline": "0.5.0",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T18:05:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ca57b95c59955c06a414c97ab4c77b6a952608ff",
"body": "…PI, site\n\n- README + CLAUDE.md: datagrid module entry; behaviors scope auto-registration;\n collection.filtered(); http pluggable fetch.\n- CHANGELOG 0.4.10: datagrid, collection.filtered, behavior auto-teardown,\n query({arrays}), marker console.error.\n- docs/SHARP-EDGES: query({arrays}) note (repl\n[…]\n (13 modules, 81 exports — adds datagrid).\n- index.html: datagrid module card + import map; footer stats (259 tests, ~4.5 KB\n core). Verified index.html + api.html render datagrid, no console errors.",
"is_bot": false,
"headline": "docs: datagrid + round-four fixes across README, CLAUDE, CHANGELOG, A…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T18:02:48Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4f9b6af7207f756f15da80c75bfae34cff48d067",
"body": "…ogs error\n\nThree review edges (§7, §11, §2):\n\n- §7: portal/dismissable/trapFocus/anchored now onDispose-register their undo, so\n building them inside scoped()/mount() means dispose() alone tears down effects\n AND behaviors — no hand-tracking. Undos stay returned and are now idempotent.\n- §11: que\n[…]\ned (unchanged).\n- §2: a bare parent.append(when()/list()) now logs at console.error (was warn) so\n headless/CI catches it (most harnesses fail on console.error); the in-DOM\n breadcrumb is unchanged.",
"is_bot": false,
"headline": "fix: behaviors auto-register teardown; query() array params; marker l…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T18:02:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "61195b6e751a0669a9a4767e02195e04cceb6e31",
"body": "…aging)\n\nReview §11 called a headless dataGrid 'the single highest-leverage addition' for\nqrp's audience — the batteries every admin table rebuilds: row selection\n(select-all + indeterminate, keyed so it survives sort/filter/page churn and\nrow-object replacement on refetch), column visibility, page-\n[…]\nthe\n .d.ts), gen-api MODULES, and test/types.ts\n- tests: selection + keyed-survives-refetch + filtered select-all, column\n visibility, page-size reset, windowed pager clamping, explicit-page honored",
"is_bot": false,
"headline": "feat(datagrid): headless data-grid state machine (selection/columns/p…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T18:02:46Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "87e6f0618eeedaa895e9512ac2a13f66b036887a",
"body": "…ll links)\n\n- §0: README linked docs/*.md, CHANGELOG, examples/ — none ship in the npm\n tarball, so an npm reader hit dead links. Converted to absolute GitHub URLs\n (work on both npmjs.com and GitHub).\n- §1: SHARP-EDGES 'Routing & URL' — navigate with a real <a href>, not\n onclick+navigate() (pre\n[…]\nve loader is now safe inside effects (the untracked fix).\n\nVerified sharp.html renders: new Routing section, 6 TOC entries, 11 cross-doc\nlinks resolve to api.html, no raw .md links, no console errors.",
"is_bot": false,
"headline": "docs: address review's doc findings (SHARP-EDGES callouts + npm-tarba…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T17:46:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "224a1d9b97f18561821c67e3d1fe28d8d6794f4b",
"body": "…h is never partial)\n\nReview §5 flagged validate().value 'dropping keys not in the schema' (v0.4.8),\nranked the highest-value fix. It does not reproduce: walk() has built `out` from\n{ ...data } since before v0.4.8, so undeclared keys already pass through (declared\nones coerced) — verified against th\n[…]\n test mirroring the exact scenario (a no-rule\nfield surviving alongside coercion), plus explicit 'carries ALL keys' wording in\nthe module doc + .d.ts (pass { strict: true } to reject undeclared keys).",
"is_bot": false,
"headline": "validate: lock in + document that value carries undeclared keys (patc…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T17:46:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1686c1c1af82840f310e0a9be9c00a3e3559b358",
"body": "… fetch seam\n\nTwo fixes surfaced by a real Vite/TS rewrite driving qrp as an npm dep.\n\n1. CRITICAL: the reactive in-flight counter's `loading.pending += 1` reads\n pending. Issuing a request synchronously inside an effect() (the normal\n refetch-on-filter-change pattern) subscribed that effect to \n[…]\nests or wrapped (retry/dedupe) without patching\n globalThis.fetch.\n\nTests: a request inside an effect no longer re-runs it via pending; a custom\nfetch overrides the global. d.ts + CHANGELOG updated.",
"is_bot": false,
"headline": "http: stop createHttp leaking the loader dep into caller effects; add…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T17:35:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "fde5b7d75c5ef18d8f1791043e2d802919899dd2",
"body": "An effect that (transitively) writes state it reads looped forever: the classic\nfootgun is a loader called from an effect that sets state the same effect\ndepends on. Synchronously it recursed until the stack overflowed; with an async\nloader it spun an unbounded fetch loop ending in net::ERR_INSUFFIC\n[…]\nt option + phase 'loop'; API.md regenerated.\n- tests: runaway is stopped+reported; 50 legit re-runs never trip the guard.\n- docs/SHARP-EDGES.md + CLAUDE.md + CHANGELOG: document the guard and the fix.",
"is_bot": false,
"headline": "core: runaway-effect guard (loop detection) — 0.4.10",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T16:45:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f667721cea84904d30e07be28efc0fac84c517bd",
"body": "…ss-links\n\n- styling.html renders docs/STYLING.md live (same dogfooded md renderer as\n api/start); sharp.html does the same for docs/SHARP-EDGES.md (which the guide\n already linked but had no rendered target).\n- generalize resolveHref across all doc pages: cross-doc .md links now map to\n their re\n[…]\ning at the site root.\n- unified doc-page nav (Home · Guide · API · Styling · Demos · GitHub); added\n Styling to the main site nav. Verified: all 4 pages render, no raw .md links,\n no console errors.",
"is_bot": false,
"headline": "site: render STYLING (and SHARP-EDGES) on the website + unify doc cro…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T15:07:58Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5e0e7f8214803fedc44706ad0f5eb094f7adf35e",
"body": "Documents the styling seam the 'helpers, not styled components' stance implies:\nthe three approaches (own CSS, the qrp.css token baseline + light/dark theming,\nor a CSS framework via class passthrough), the --qrp-* design tokens, and a\nreference of every semantic class the batteries emit (grounded in the source,\nincl. the forms classes' un-prefixed quirk). Linked from README + guide + CLAUDE.",
"is_bot": false,
"headline": "docs: add STYLING.md (bring-your-own CSS / qrp.css tokens / frameworks)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T14:59:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a32624ad7baa57e5bc4f77f2e61bb96c151d5c56",
"body": null,
"is_bot": false,
"headline": "docs: CHANGELOG 0.4.9 (sideEffects)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T14:37:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b62594b4f0edc0a64b3926bf509364a70de8685f",
"body": null,
"is_bot": false,
"headline": "0.4.9",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T14:37:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5b66dda31c30ced238ce5c173bc9596c44b62f42",
"body": "Marks all JS side-effect-free so a consumer's bundler (webpack especially, which\nrequires the flag) drops unused re-exports — importing one util from the barrel\nno longer drags the rest in (verified: memoize-only import = 843 B, no\nvalidate/loadScript/limit/debounce). CSS kept side-effectful (**/*.css) since a\nCSS import injects styles.",
"is_bot": false,
"headline": "build: add sideEffects for reliable consumer tree-shaking",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T14:36:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "429f87b6cd649d7ef98708870c5f534e25de9353",
"body": "Nav lagged the reorder: now Guide · ESP32 · Composition · Performance · Reactivity\n· Table · Data · Modules · API · GitHub — in section order, differentiators first.\nAdded the missing Composition link; every in-page anchor resolves.",
"is_bot": false,
"headline": "site: nav order matches new section flow (+ add Composition, drop stale)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T14:16:36Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3e8f417f566249c4eb65bd15f65d0ae5e1a740ca",
"body": "Marketing order: reactivity is table stakes (assumed), so the differentiators go\nfirst — esp32 (tiny) → composition (simple) → performance (categorically fast:\n'change one field, touch one node') → reactivity (the how). Moved the perf\nsection's scattered helpers (perfData/perfSection/vsRow/perfHeadline) together\nwith its append so they define before use. Verified render + order, no errors.",
"is_bot": false,
"headline": "site: lead with differentiators — Performance now sits above Reactivity",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T13:06:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "da95b909c8c8fb0ff67d47d7b38adcf9a0e1efcd",
"body": "esp32 (the 'wow' hook) → composition (how you actually build) reads as a stronger\none-two before the primitives deep-dive. Section unchanged, just reordered.",
"is_bot": false,
"headline": "site: move Composition section directly below the ESP32 demo",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T12:54:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b3688d3be96817d14fb2f5d0e9ca1c0ce113a433",
"body": "…nctions\n\nShows the 'components are just functions' payoff concretely: a Card() wrapping\nField()s (each wrapping an input) plus a Toggle() factory, composed into a live\nAccount settings card with two-way bind + a save + a live state readout. Verified\nin Chromium (edit name, flip toggle, save), zero console errors.",
"is_bot": false,
"headline": "site: add live Composition section — a real card+form from factory fu…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T12:43:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "de231f84e82ff3f59e66b91c0abc8a8a846c2949",
"body": "Teaches the 'helpers, not components' payoff the guide was missing: a component\nis just a function returning DOM; a factory takes props (values or thunks/state)\nand returns an el() tree. Covers composition, the one-node-one-place reuse\ngotcha (why factories/thunks exist), free scope-owned cleanup + onDispose, and\nwhen to reach for scoped()/define(). Renumbered 'Where to go next' to §9.",
"is_bot": false,
"headline": "docs(guide): add 'Reusable components (the factory pattern)' section",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T12:41:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f502ee63a6eef29abae291145cd3eaba70abd290",
"body": null,
"is_bot": false,
"headline": "chore: gitignore profiles/ (local profiler captures, never commit)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T12:35:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0157332325f398bf8eefd6ef9785e6fe910ae40d",
"body": "…ustom domain)",
"is_bot": false,
"headline": "docs: point live-demo links + homepage to https://qrp.nemanja.top/ (c…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T12:34:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b15ea0c1342a224c235b571ec1a1084722adb9b9",
"body": null,
"is_bot": false,
"headline": "0.4.8",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T10:24:47Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "52188b7b36c20e65761a6cb54033de62ee527219",
"body": null,
"is_bot": false,
"headline": "docs: CHANGELOG 0.4.8 + test badges (243)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T10:24:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a1f8c262c851ed89b24b405825cbbb64f29976a5",
"body": "The one unsupported marker position — parent.append(marker) — failed as a silent\n[object Object] text node (shipped exactly this: a whole tab pane rendering as\n[object Object], invisible to navigation-only smoke tests). Markers now carry a\ntoString() that console.warns and returns a '[qrp when() — r\n[…]\ndiagnoses at the call site.\nCan't fire in normal use (qrp routes markers via the renderable symbol before any\nString coercion). +test (happy path silent; misuse warns+breadcrumb). SHARP-EDGES\nupdated.",
"is_bot": false,
"headline": "feat(core): markers self-diagnose a bare DOM append (P2)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T10:24:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2c4fb6bb922ef284bf227b79939219cf33d1387e",
"body": null,
"is_bot": false,
"headline": "0.4.7",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T09:18:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "700229f87b9c4c22ba75e10cedd8ae76bd9d899c",
"body": null,
"is_bot": false,
"headline": "docs: CHANGELOG 0.4.7 + test badges (242)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T09:18:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e2bcd1e6d1cb316043ffb0d3f52bcc0f219b9603",
"body": "…plementations\n\nCloses the one seam where when/list were privileged: the normalizer special-cased\ntheir brands, so a userland switchOn/virtualList needed a host element. Now child\nposition dispatches on Symbol.for('qrp.renderable') — any object with\n[renderable](parent) renders like when/list, with \n[…]\nts it without importing. +test: a userland switchOn nested inside a\nfirst-party when, no wrapper, no stranding. Docs: exported symbol +\nQrpRenderable type, CLAUDE 'small core, everything else a peer'.",
"is_bot": false,
"headline": "feat(core): expose the renderable protocol — when/list become peer im…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T09:17:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0a9b621b1988395869933d17cbf2a65289671f11",
"body": null,
"is_bot": false,
"headline": "0.4.6",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:41:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2866a067479cd1545cc00e27eb27692b44d0f400",
"body": null,
"is_bot": false,
"headline": "docs: CHANGELOG 0.4.6 + test badges (241)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:41:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6bad92c479b4a3ae898c97b9524d03f4cd958ab1",
"body": "…M on dispose (P0)\n\nFound adopting 0.4.x: a when()/list() nested in a parent marker's branch stranded\nits DOM when the parent switched (both tabs' content stacking). Cause: the parent\nonly tracks the nodes present when IT mounted the branch; a nested marker that\nre-rendered since inserted nodes the \n[…]\n unaffected (clear() already wipes; the removes are no-ops there).\n\nWrapper divs are no longer needed as the safe idiom for nested markers. +2 tests\n(nested when->when, when->list grow/switch/return).",
"is_bot": false,
"headline": "fix(core)!: nested-marker teardown leak — a marker removes its own DO…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:41:33Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b17b8732e5e114f699297749d9e5f58a267ee112",
"body": null,
"is_bot": false,
"headline": "0.4.5",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:21:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b604b5cb4bf2c470218f86ab963fb3b2be182f59",
"body": null,
"is_bot": false,
"headline": "docs: CHANGELOG 0.4.5 + test badges (239)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:21:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1a495ca7d752ab053965e5cb1d60f349ce7b56df",
"body": "The two must-have table batteries, done without regressing the static fast path:\n- fields may be a THUNK () => Column[] — a reactive column set (visibility\n toggle, role-gated). Header + each row's cells become reactive regions that\n re-render on change; row ELEMENTS are reused. Static arrays keep\n[…]\n Row click toggles it (interactive cells excluded); also\n node.toggleRow(key) + reactive node.expanded. + qrp.css .qrp-expand.\n+5 tests (incl. row-reuse across column change, interactive-cell guard).",
"is_bot": false,
"headline": "feat(table): dynamic (reactive) columns + expandable rows (§9.6)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:20:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b6c500d50518a99c1ea61d43b79d95279d98dfa5",
"body": null,
"is_bot": false,
"headline": "0.4.4",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:14:59Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "663d2505fc8a5ee341821e3880a376231acd23a6",
"body": null,
"is_bot": false,
"headline": "docs: CHANGELOG 0.4.4 + test-count badges (236)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:14:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2807623d89d13922c7b9bd4018644fea1cb90404",
"body": "Full control of a th's content (select-all box, filter icon…); its own clicks\nstopPropagation so they don't trigger the column sort. Overrides label. +test.",
"is_bot": false,
"headline": "feat(table): custom header content via field.header(column) (§9.6)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:14:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "906cd4735e936cb4ec5e99b63999aee9a93d6e50",
"body": "The ~70-lines-per-page pager (prev/windowed-pages/next, clamp, hide at ≤1 page)\nand 'Showing X–Y of Z' summary the port rewrote every time — now stock helpers\nover a table().view (or any collection), reactive. + qrp.css baseline styles\n(.qrp-pager/.qrp-summary). +4 tests.",
"is_bot": false,
"headline": "feat(table): tablePager + tableSummary batteries (§9.6)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:13:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "967b94d28dd4773c306479e8f74aec8a09d188cc",
"body": "Persist table filters/sort/page to the URL without a page rebuild: setQuery\nmerges/replaces query params (nullish removes, array repeats), defaults to\nreplace+merge, and rides the same-pattern keep-alive so currentRoute.query\nupdates reactively with no remount. +test.",
"is_bot": false,
"headline": "feat(router): setQuery() — query-only URL updates without remount (§4.3)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:11:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2d51c674a4a605bb84afa97f5ecbf875744aa05c",
"body": "…name})\n\nThe 2nd handler arg was the opaque internal runner. Now it's a stable context:\n{ phase } — 'create' (first run) vs 'update' (a reactive re-run) — plus 'name'\nfrom effect(fn, { name }), for crash-report attribution/triage. +test asserts.",
"is_bot": false,
"headline": "feat(onEffectError): documented context { phase, name } + effect(fn,{…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:10:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6ef425ce88074f8e544a96ecf3e7813b07205d92",
"body": "…ount appends return (§2.2)\n\n- toNodes() now materializes when()/list() markers via a fragment, so a marker\n RETURNED from a when branch, a list render, a mount component, or a reactive\n hole renders instead of stringifying to [object Object]. Only a bare non-qrp\n parent.appendChild(marker) is un\n[…]\nso the\n append-to-view style doesn't double. Done inside the mount scope so a returned\n marker's effects are owned.\n- docs: when()/mount d.ts + SHARP-EDGES updated (no longer limitations). +6 tests.",
"is_bot": false,
"headline": "fix(core): markers render when returned (not just as el children) + m…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:08:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0e40aba47040adf2626d68b9a7c9e46cf632ca03",
"body": null,
"is_bot": false,
"headline": "0.4.3",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:01:11Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "20966d4e25a40a0e0ace1ac36783706e09964a8a",
"body": "…empty (round-three findings)\n\nFrom the production port adopting 0.4.2 (deleted both hand-rolled validators):\n- validate(schema, data, { strict }) — opt-in reject keys not in the schema,\n recursively (default permissive, so pass-through patches keep working).\n- present-but-empty '' is now validated\n[…]\n — now deletable.\n\nAlso: add CHANGELOG.md (breaking/behavioral changes marked, newest first) — the\nport flagged three consecutive silent semantic fixes; this closes that. Linked\nfrom README. +2 tests.",
"is_bot": false,
"headline": "feat(validate)!: strict unknown-key rejection + validate present-but-…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T08:01:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6538f6376d2f97f2bd0c6360d52dfba8c532897f",
"body": null,
"is_bot": false,
"headline": "0.4.2",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T01:12:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fc8702046b7859c52894a4c1698965348f5562cf",
"body": "…inding)\n\nThe production port could NOT adopt validate() because its real validation sites\ncoerce ('5'→5, 'true'→true) and send the coerced patch to the server; check-only\nwould have changed the wire format. Now validate() coerces form strings toward\neach rule's declared type and returns { errors, v\n[…]\nend as the patch. Nested fields coerce too.\n\nBREAKING: validate() returns { errors, value } instead of an errors array\n(validate is one release old; pre-1.0). Docs/site/types updated. +coercion tests.",
"is_bot": false,
"headline": "feat(validate)!: coerce + return { errors, value } (round-two field f…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-15T01:12:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "22586768445c75575d51770074b50b59c793861a",
"body": null,
"is_bot": false,
"headline": "0.4.1",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:22:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "63cfe8c028e1d1d4dc3aa3d717b5831e7da95123",
"body": "0.4.0 shipped dist/utils/ WITHOUT debounce/limit/validate/load-script: build.js's\nENTRIES was a hand-maintained list and the new util files were never added, so\nthe exports './utils/*' deep subpaths pointed at files not in the tarball (the\numbrella '@nemanjan00/qrp/utils' worked; '.../utils/debounce\n[…]\n\n- build guard: assert every package.json exports subpath resolves to a built\n dist file; fail the build (→ prepack → publish) otherwise.\n\ndist/utils now has all 8 files; verifyExportsResolve passes.",
"is_bot": false,
"headline": "fix(build)!: derive dist entries from filesystem + guard exports resolve",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:22:23Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1b3d0e892130cd6a9c03d5c23452ecb84c7df982",
"body": "The utils overview prose was stale — it listed only the original helpers, not\nlimit/debounce/throttle/validate/loadScript or memoize's ttl/invalidate (the\nper-export entries were present; only the intro undersold them). Note the barrel\nimport for both modules and the scoped() modal caveat for behaviors. Regenerated.",
"is_bot": false,
"headline": "docs: refresh utils/behaviors module overviews in API.md",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:18:07Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "050e4d1dfd12134c0a54998bc7eef3cb13f5ea99",
"body": "…utils/routing snippets)\n\n- site: live 'Dashboard utilities' section — a debounced search (keystrokes fire\n every time; the search waits for a pause), verified in Chromium. Highlighter +\n importmap updated for the new utils.\n- README: value-keyed when() tab example; new snippets for debounce/limit/\n validate, responseType, currentRoute/scoped/onEffectError; keep-alive note.",
"is_bot": false,
"headline": "site,readme: showcase 0.4 features (debounce demo, value-keyed when, …",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:11:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c472d135db61d1ad195620aea0765075672c7e89",
"body": "… KB library)\n\nNew exports (currentRoute, onEffectError, scoped; validate, loadScript,\nlimit/debounce, memoize ttl) grew the core to ~3.9 KB min+gzip and the whole\nlibrary to ~16.8 KB. README badge/copy, index.html meta/hero/footer updated.\nBenchmarks re-verified: single-cell still ~0.8 us / 1 node of 40,002; suite\nratios unchanged within noise — no table change needed.",
"is_bot": false,
"headline": "docs: update size claims to measured 0.4.0 figures (~3.9 KB core, ~17…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:07:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b02926a12717ad695fdf0e07ac78d7e372c884f7",
"body": null,
"is_bot": false,
"headline": "chore: bump test-count badges to 225",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:03:22Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1a4cbe83a4abd494d67079b7b5b4516ec925a7cc",
"body": null,
"is_bot": false,
"headline": "0.4.0",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:03:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ae030cc73c4f16814fbb4cb0bcb6c7943da25109",
"body": "- docs/SHARP-EDGES.md: the handful of behaviors worth knowing once (raw-array\n mutation, node-lives-once, marker-as-child, value-keyed when, unique list keys,\n scoped() for handler-built UI, http reject shape, SPA serving) — reflecting the\n CURRENT post-fix state, not the report's pre-fix list. Linked from README +\n Getting Started.\n- README/CLAUDE.md/site utils listings updated (validate, loadScript, memoize\n ttl). API.md regenerated.",
"is_bot": false,
"headline": "docs: add SHARP-EDGES.md + sync README/CLAUDE/site for new utils (§8.2)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:02:58Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4ada320501607f98c17241fc105a7358c9e860e4",
"body": "… §6.2)\n\n- utils/validate.js: tiny declarative schema validator (required/type/min/max/\n enum/pattern/custom check/nested fields) → [{path,message}]. Pairs with forms;\n the zero-build answer to joi/zod for PATCH payloads.\n- utils/load-script.js: inject a UMD/global <script> once (deduped), reactiv\n[…]\n — the honest hatch for Chart.js et al. under an\n import-map app.\n- behaviors/anchored: { matchWidth } sizes the floating element to its trigger\n (dropdown-spans-input).\n+4 tests, API.md 76 exports.",
"is_bot": false,
"headline": "feat(utils,behaviors): validate, loadScript, anchored matchWidth (§7,…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T23:01:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "895d7cb62ba893d2da7064df6396c827e9b9a668",
"body": "The generator listed supporting types by NAME only — the gap that shipped the\ndisclosure() bug (readers assumed d.open was a boolean, not a method). Now it\ncaptures each exported interface/type's FULL definition (brace-matched), incl.\nundocumented ones (second pass), and emits them as code blocks under a\n'Supporting types' heading. Bumped the api.html/start.html markdown renderers to\nh4 + styled it. Disclosure's { state:{open}, toggle(), open(), close() } shape\nnow visible.",
"is_bot": false,
"headline": "docs(gen)!: inline supporting-type definitions in API.md (§8.1)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:59:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "80eeca1ac7e1eac8353d5d7057f6172d150c531e",
"body": "- memoize: options.ttl expires entries (post-resolve for promises); the returned\n fn gains .invalidate(...args) (one key) / .invalidate() (all). Covers the\n refetch-with-TTL + bus-driven-invalidation pattern hand-rolled in the port.\n- lru: add clear().\n- scoped(fn) -> { value, dispose }: build UI \n[…]\nutside a render (a modal from an\n onclick) with owned effects instead of ownerless leaks (§6.1). ESP32 demo's\n scan modal now uses it — its when()/list() effects tear down with the modal.\n\n+4 tests.",
"is_bot": false,
"headline": "feat: memoize ttl+invalidate, lru.clear, scoped() sugar (§7, §6.1)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:56:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0b509670698f32883b497e664d08ca2a6db27058",
"body": "BREAKING (behavioral): when a navigation matches the SAME route pattern (a\nparam/query change — e.g. switching :tab on /users/:pk/:tab), the router no\nlonger tears down and remounts the page. In-pane state (form edits, scroll,\nexpanded rows) survives and the handler reacts through the reactive currentRoute;\nno refetch churn. A different pattern still fully remounts. Pass\nrouter(..., { remount: true }) to restore always-remount.\n\n+2 tests.",
"is_bot": false,
"headline": "feat(router)!: keep-alive on same-pattern navigation (§4.2)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:52:48Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "9869aafe3f93b263ca075d4d90728510e4827d85",
"body": "…c, §5.1b)\n\n- table: custom render() cells are now reactive — re-run when the row's item is\n replaced (refetch), so action cells reflect fresh state instead of the item\n they were built with. (Was: built once per key.)\n- forms: form() renders the FIELDS spec, not Object.keys(settings) — a field\n \n[…]\njects created, bound two-way) and seeds defaults\n along the path. With no fields, keeps the reactive-key-set fallback.\n\nBREAKING: form() structure is now fields-driven when fields is given. +6 tests.",
"is_bot": false,
"headline": "feat(table,forms)!: reactive render cells + fields-driven forms (§2.3…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:51:13Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "604513728342351e59c0b79fdb342d3a3e4dfca9",
"body": null,
"is_bot": false,
"headline": "test(list): cyclic-object rebind terminates (loop safety regression)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:47:14Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cba5465b9f2b15b57e0dace84ed85005a17c0005",
"body": "… §2.4)\n\nBREAKING (behavioral): a row whose key survives a refetch now reflects the fresh\nobject instead of the one captured when the row was built. The merge is a\nDEPTH-LIMITED recursion (REBIND_DEPTH=8): it recurses into nested plain objects\nso their proxy identity is preserved (a captured `const \n[…]\nic subtrees fall back to reference assignment. Same-identity rows still\nupdate in place through their own bindings.\n\nAnswers the reviewer's §2.3 staleness trap and the nested-object concern. +3 tests.",
"is_bot": false,
"headline": "feat(list)!: rebind surviving rows via bounded recursive merge (§2.3,…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:46:25Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "05d5b1afc56b8a91f1c3bc276bf635f2871191a8",
"body": "… (§2.1)\n\nBREAKING: when() now re-renders the branch when the condition's VALUE changes\n(Object.is), not only when truthiness flips. This makes value-switches work\ndirectly — when(() => state.tab, tab => TABS[tab]()) re-renders on every tab,\nthe pattern that previously shipped a bug (stuck on the fi\n[…]\nue change rebuilds.\n\nMigration: code relying on when() NOT rebuilding across distinct truthy values\nshould key on a boolean instead (when(() => !!x, ...)). Boolean conditions are\nunaffected. +2 tests.",
"is_bot": false,
"headline": "feat(when)!: value-keyed rendering — re-render when the value changes…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:42:02Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a72052769746f32ed8434f9a00534bfc51d6cfe7",
"body": "…1/§2.2)\n\nCompletes the 'skip the behavior change, document the gotcha' half for the two\nthat shipped bugs in the field report: when() swaps on truthiness not value\n(so it won't switch between truthy tabs — branch per value), and markers are\nonly valid as el()/html children. Regenerated API.md.",
"is_bot": false,
"headline": "docs: loudly document when() truthiness trap + marker-child rule (§2.…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:38:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "95a8fb084395cc71c9ac9eeac31fd91aed2bba69",
"body": null,
"is_bot": false,
"headline": "0.3.0",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:36:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "202831e5223bb69e9bce3c52068f1b294b4e4bbe",
"body": "…pe, utils limit/debounce/throttle, forms style passthrough\n\nAdditive changes from a production port's punch list (no breaking semantics):\n\n- core: onEffectError(handler) — central hook fired before a throwing effect's\n error propagates (wire Sentry etc.); today a throwing binding is only visible\n \n[…]\nal), types-suite usage, API.md regenerated (73 exports),\nREADME/site/CLAUDE.md synced. Skipped (need design, would break behavior):\nwhen() value-keying, list()/table render-cell rebind, nested routes.",
"is_bot": false,
"headline": "feat: field-report P0s — onEffectError, currentRoute, http responseTy…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:36:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "d8153a6c58ace5273d19ff17ca22a0eeaf7317a5",
"body": null,
"is_bot": false,
"headline": "chore: gitignore local field notes (never commit/publish)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T22:23:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bb2078b973ceb1a30a706233b2f0ab5a3b1efb11",
"body": "…ast)\n\nThe old toasts demo sent a static html snippet — it didn't show the actual\ntrick. Now 'Delete last' emits a toast whose content is a live el() node with\na working Undo button; the node travels over the bus (bus.emit('warning', node))\nand the toast layer renders it, handler and all. Undo restores the item and\nfires a success toast. Builds a fresh node per emit (a DOM node lives in one\nplace). Reframes the section as 'Renderables over the bus'.",
"is_bot": false,
"headline": "site: demo sending a live DOM node over the event bus (Undo action to…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T20:32:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ee3caee84528c85ee6514d832436d41c61286c33",
"body": "…orners\n\n- sparkline: derive() the history min/max ONCE per tick instead of every one\n of the 40 bars re-scanning the whole array twice (was 80 scans to move 40\n bars — the opposite of the fine-grained pitch). Now one scan feeds 40 bindings.\n- modal: make close/pick local to each openScan() so they close over that\n invocation, not a module-scoped reassigned handle — the pattern stays correct\n if copied for a second modal. Compose the three behaviors' teardowns into one.",
"is_bot": false,
"headline": "examples(esp32): tighten the two spots exemplary code shouldn't cut c…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T20:24:27Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "ec42b8f86d1c954f14376402ee3dadd53ac86003",
"body": "- docs/GETTING-STARTED.md: a ten-minute, zero-to-dashboard tutorial covering\n the five core ideas (state/effect, el, derive, when, list) then a full small\n dashboard, with a 'where to go next' map into the module docs.\n- start.html: renders the guide live with the same qrp markdown renderer as\n a\n[…]\n in api.html/start.html (link-in-text-block).\n- wire links: README header + Install note, index.html nav + hero 'Get\n started' CTA, api.html nav.\n- CLAUDE.md: document the guide + start.html pattern.",
"is_bot": false,
"headline": "docs: add Getting Started guide + rendered start.html page",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T20:17:08Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a1a679b73d550a95e3fb35999c8ddf79771a4fe7",
"body": null,
"is_bot": false,
"headline": "0.2.1",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T20:02:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "57334a7be17992f75f106dfd4e0282f8c2100924",
"body": "Leftover from the original form-only demo; the reworked live dashboard is\n~6 KB gzipped, as the panel next to it already states.",
"is_bot": false,
"headline": "site: fix stale ESP32 flash size in code comment (~4 KB -> ~6 KB)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T20:01:34Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "5622b43d40f7e85dfd3b7f1b036e636d6cf9ccf2",
"body": "Audited all three pages (site, api.html, esp32 dashboard) with Lighthouse.\n\nAccessibility -> 100:\n- forms: field() now associates its <label> with the control via for/id\n (only for labelable INPUT/SELECT/TEXTAREA, not the radio-group wrapper) —\n fixes the Lighthouse select-name/label failures at t\n[…]\nO -> 100: meta description on the esp32 dashboard.\n\nFinal: site 98/100/100/100 (2 perf pts are the intentional raw-source load),\napi 100/100/100/100, esp32 100/100/100/100 — for a client-rendered SPA.",
"is_bot": false,
"headline": "a11y + perf: Lighthouse 100 on api & esp32, 98/100/100/100 on site",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:57:44Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8dac45759bd807b914764116211e8c40e0507443",
"body": "A static settings form is the weakest pitch for a reactive framework, so make\nthe demo show what only reactivity can do:\n- live telemetry (temp/humidity/rssi/heap) streaming into bindings + sparkline\n- LED toggle + brightness slider that write to the device\n- config form that rewrites itself via whe\n[…]\nKB gzipped blob\n- reframe README + site section (live dashboard, not a form); iframe gets a title\n\nFixes the qrp gotcha of mixing native append() with when()/list() markers\n(build the tree with el()).",
"is_bot": false,
"headline": "examples(esp32): rework into a live reactive dashboard + WiFi-scan modal",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:38:04Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "032c8a0146d289e246b600f849f78ec9afd0469c",
"body": "… & site\n\n- examples/esp32/: form() as a full device config UI, bundled + minified +\n gzipped into a ~4 KB PROGMEM blob served from flash. PlatformIO project\n (platformio.ini + src/main.cpp), build.js (bundle->minify->inline->gzip->\n PROGMEM header), self-contained dashboard.html doubles as the l\n[…]\n extreme case' section after the hero — main.cpp serve snippet\n beside a live iframe of the actual dashboard; nav link added.\n- fix README keyed-list sample: () => view.items() (items() is a method).",
"is_bot": false,
"headline": "examples: add ESP32 self-hosted settings dashboard + wire into README…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:24:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f5c5c80c6499e0fcba83e11a0fad899992e5f13f",
"body": null,
"is_bot": false,
"headline": "0.2.0",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:15:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "80672759ab7ce63666b50cda1e983d63d46cf998",
"body": "- bin/build.js: esbuild bundle+splitting per subpath -> dist/ (shared core\n chunk), minified. npm run build; also prepack so pack/publish rebuild it.\n- package.json: exports.default -> dist/*.js, exports.types -> hand-written\n .d.ts; files ships dist + .d.ts + css, NOT raw source; esbuild devDep.\n\n[…]\n correct all size claims to measured figures: core ~3.7 KB min+gzip\n (was quoting ~12 KB raw-gzip), whole library ~15 KB; honest raw-source\n clause in README. Update CLAUDE.md (docs+build pipeline).",
"is_bot": false,
"headline": "build: ship minified, code-split dist/ on npm (~3.7 KB min+gzip core)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:13:32Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e32e6f7653001a4c895b6ea7c36ae75b4aba1da3",
"body": null,
"is_bot": false,
"headline": "0.1.1",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:02:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3970b677ebc87be173531a11c516a54c434c6131",
"body": "- npm version + license badges, npm link in quick-links\n- LICENSE (MIT) + license field in package.json + License section",
"is_bot": false,
"headline": "readme: npm badge + link; add MIT license",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:02:00Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b8f140c42beaa094eaddd88936edc26e585942a2",
"body": "- package.json: scoped name, exports map (clean subpaths + types), files\n allowlist, publishConfig.access=public, repo/homepage/keywords/author\n- README + generated API.md + site + examples: import from @nemanjan00/qrp[/sub]\n- demo HTML pages gain a <script type=\"importmap\"> so the bare specifiers\n\n[…]\noped specifiers so docs stay single-sourced\n\nqrp was taken on npm; scoped keeps the brand. Verified: all demo pages boot\nunder the import maps, typecheck + lint clean, npm pack ships 47 runtime files.",
"is_bot": false,
"headline": "publish: rename package to @nemanjan00/qrp, wire clean subpath imports",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T19:00:10Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "910bdc1b7fea47d9bd02254f72f778c5af5784b5",
"body": "Runs on push to master/main and every PR, matrix over Node 22 & 24\n(node --test glob needs Node >= 21). Adds a CI status badge to the README.",
"is_bot": false,
"headline": "ci: add GitHub Actions workflow (lint + typecheck + test)",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:47:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8683e88d410f4ba9a315e6beead59ded20627df6",
"body": "- assets/qrp-logo.svg: wordmark (r in accent) + QRP radio-wave mark,\n matched to the site palette (#0a0d12 / #ffb23e / #34d399)\n- centered header: shields.io badges (deps/build/size/tests/types),\n live-demo + API + quick-jump links\n- emoji icons on every section heading; proto row lists onceOnly",
"is_bot": false,
"headline": "readme: add logo, badges, section icons, live-demo links",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:46:20Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "64f419bcde72272ec6dbd0531fe3b8aa7647fcf5",
"body": "The proto module (wrapMethod/delegate/onceOnly) shipped and tested but never\nappeared on the marketing site — not even as a module card. Add a live\nwrapMethod demo (idempotent prototype patch, the userscript trick) and the\nmissing grid card.",
"is_bot": false,
"headline": "site: add Prototypes section + module card for the proto module",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:40:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "b74088c4f3ddd318cf02578a0713721c53801b5f",
"body": "- add bin/gen-api.js: parse .d.ts doc-comments -> docs/API.md\n- backfill @module overviews across satellite .d.ts so curated prose\n (html escaping guarantee, forms FieldSpec/types, http error shape) lives\n in one place and flows through the generator\n- enrich qrp/index.d.ts: list() thunk source contract, effect/derive edge\n cases, el() prop-rule subsection, scope-vs-mount guidance\n- wire npm run docs",
"is_bot": false,
"headline": "docs: generate API.md from .d.ts single source",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:37:30Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "10b26d4d927cd0b393e0967f64467b8c86580934",
"body": "- api.html: a browsable API reference — sticky sidebar TOC, filterable search,\n styled tables/code — rendered at runtime from docs/API.md by a compact\n Markdown→DOM renderer built with qrp itself (el/list/state, no md library).\n The site DERIVES from the markdown: one place to update, no duplicat\n[…]\number + the minified\n context, not the flattering stale figure.\n\n- CLAUDE.md: documented the types/docs setup and the JSDoc-as-single-source\n north star (generate .d.ts + md from JSDoc — next step).",
"is_bot": false,
"headline": "API reference page (renders docs/API.md live) + accurate size numbers",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:22:07Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "1658fe32a56140934bba630cc1f2e2a0abc26160",
"body": "Ship types for the whole surface, hand-written next to each ESM module so\nimporting \"./qrp/index.js\" resolves ./qrp/index.d.ts — no @types package, no\nbuild step, no change to how qrp is loaded.\n\n- .d.ts for qrp, html, forms, collection, table, http, events, toasts, browser,\n each behaviors/* and u\n[…]\nerence — every export, signature, and a usage snippet\n per module, plus the escaping guarantee and a TypeScript section.\n\ntypecheck passes; lint clean; 192 tests. .eslintignore excludes the .ts test.",
"is_bot": false,
"headline": "Add TypeScript declarations (.d.ts) for every module + API reference",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:14:19Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c82c909757c0ae9dfde824f5b839032a3f347a5b",
"body": "Same class as the markup-demo fix, in the section whose lede promises \"disposes\nthe previous route's scope on navigation.\" It did the opposite: it hand-rolled\noutlet.replaceChildren() + mount() inside an effect and never kept the disposable\nmount() returns — so every tab click stranded the previous \n[…]\ne outlet) — which is exactly\nwhat the real router() does on navigation. Verified in Chromium: switching\nthrough all routes leaves exactly one view in the outlet (no accumulation), zero\nconsole errors.",
"is_bot": false,
"headline": "Router demo: dispose the mount handle instead of hand-rolling + leaking",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:02:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "eb894b9a65eb07eb1a0989f5a98315609b7fcb54",
"body": "1. Removed the duplicate storable-templates section — #templates (Grace Hopper)\n and #storable (card list) demoed the same feature. Kept the richer #storable\n (list() + add-row).\n\n2. Markup demo now uses when() for the tab switch instead of a hand-rolled\n IIFE + effect + replaceChildren — dogf\n[…]\nno longer contradicts the numbers below it.\n\nVerified in Chromium: one templates section, one viewport meta, badges/footer at\n192, markup when()-switch works, theme swatch reacts, zero console errors.",
"is_bot": false,
"headline": "Fix the remaining five site issues from review",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T18:00:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0961cca28a9772165110e4805f0296668eab0833",
"body": "1. Perf chart no longer drops the two worst numbers. It now shows all EIGHT ops\n the README shows — including create 10k (1.3×) and clear 10k (1.8×), the one\n I explicitly called the honest weak spot. Omitting it after naming it was the\n kind of thing that taints the numbers you did show. 1.8×\n[…]\nse to GitHub on narrow screens, the\n table scrolls horizontally in its own box, and section/bar/code spacing scales\n down. Verified at 390px: zero horizontal page overflow.\n\n192 tests still green.",
"is_bot": false,
"headline": "Site perf/table/responsive fixes from review",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T17:51:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e774392bb07fc764c98154eab0c8be8a3a68506a",
"body": "A 1000× claim invites a fight; answer the top-comment objections before they're\nraised, in both places people look:\n\n- flushSync: answered in react-compare.html AND the README. flushSync doesn't\n add work — it stops batching from smearing the reconcile across a later frame\n so it can be timed. Con\n[…]\ned. That walk is the ~800µs. The number\n defends itself.\n\n\"You wrote slow React\" (per-row stores narrow it) folded in as the second\nanswered objection. No code changes; docs/comments only. 192 tests.",
"is_bot": false,
"headline": "Preempt the two objections to the 1000× number",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T17:28:16Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5a20fbd89c3f35fe7b77d865ef5ecabe40c2d7ed",
"body": "…ity pass\n\nAddresses a review of the README/site — every ask was to replace an assertion\nwith evidence:\n\n- MEASURED the virtual-DOM claim. Vendored React 18 (production) and a fair\n memoized+keyed 10k-row table (examples/react-compare.html). Same single-cell\n update, same MutationObserver: qrp ~0.\n[…]\ns 8ms paint → ~10% reactivity).\n\n- clear() 1.8× called out as the honest weak spot.\n\nSite perf shows qrp-vs-React bars. .eslintignore excludes examples/vendor/\n(the React production build). 192 tests.",
"is_bot": false,
"headline": "Measure the categorical claim (React), XSS test file, README credibil…",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T17:24:19Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e6c8362499e46029c2f795702c22a77258143140",
"body": "Site (index.html):\n- Performance section now LEADS with the categorical stat — \"1 DOM node touched\n of 40,002\" when you change one field in a 10k-row table — big, with the honest\n framing (~0.8µs, no diff, no re-render, O(1); the win is vs virtual-DOM, not\n vs hand-written vanilla). Full suite ba\n[…]\nment\n(1 node of 40,002, ~0.8µs) and an explicit honest footnote — it's a win over\nvirtual-DOM frameworks, NOT over hand-optimized vanilla (270–460ns), and we say\nso. Full paint-timed suite kept below.",
"is_bot": false,
"headline": "Marketing site: single-cell headline + demo every feature; README perf",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T17:14:48Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "48a74050ef9b7e83d42c9de854fd825a9e832c2a",
"body": "- Reactive text holes now update the existing text node's data IN PLACE (both\n qrp core and html) instead of remove+insert. Changing one cell in a 10,000-row\n table touches exactly 1 DOM node (was 3), and is faster (1.3µs → 0.8µs). The\n effect closure already holds the node reference — no lookup,\n[…]\n it.\n\n- Removed utils/round-robin.js and utils/weighted-pool.js — load-balancer\n helpers that don't serve dashboards. \"Do one thing well.\" utils is now\n memoize / lru / cache / paginate.\n\n185 tests.",
"is_bot": false,
"headline": "In-place text updates; single-cell benchmark; cut load-balancer utils",
"author_name": "Nemanja Nedeljkovic",
"author_login": "nemanjan00",
"committed_at": "2026-07-14T17:10:23Z",
"body_truncated": true,
"is_coding_agent": false
}
],
"releases_count": 21,
"commits_last_year": 118,
"latest_release_at": "2026-07-17T00:27:34Z",
"latest_release_tag": "v0.7.0",
"releases_from_tags": true,
"days_since_last_push": 4,
"active_weeks_last_year": 1,
"days_since_latest_release": 4,
"mean_days_between_releases": 0.2
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 42,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "@nemanjan00/qrp",
"exists": true,
"license": "MIT",
"keywords": [
"dashboard",
"reactive",
"proxy",
"declarative",
"framework",
"frontend",
"no-build",
"zero-dependency",
"dom",
"forms",
"table"
],
"ecosystem": "npm",
"matches_repo": true,
"registry_url": "https://www.npmjs.com/package/@nemanjan00/qrp",
"is_deprecated": false,
"latest_version": "0.7.0",
"repository_url": "https://github.com/nemanjan00/qrp",
"versions_count": 18,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": 1,
"monthly_downloads": 2683,
"first_published_at": "2026-07-14T19:00:34.180000Z",
"latest_published_at": "2026-07-17T00:27:41.501000Z",
"latest_version_yanked": null,
"days_since_latest_publish": 4
}
]
},
"popularity": {
"forks": 0,
"stars": 0,
"watchers": 0,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": {
"days": [],
"complete": true,
"collected": 0,
"total_stars": 0
},
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"tsconfig.json"
],
"toolchain_manifests": [],
"largest_source_bytes": 46054,
"source_files_sampled": 84,
"oversized_source_files": 0,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 15489
},
"dependencies": {
"manifests": [
"package.json"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"npm"
],
"dependencies": [],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 0,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 0
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "nemanjan00",
"commits": 118,
"avatar_url": "https://avatars.githubusercontent.com/u/448151?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml"
],
"has_docs_dir": true,
"linter_configs": [
".eslintrc.json"
],
"has_editorconfig": true,
"has_linter_config": true,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"package-lock.json"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 10,
"reason": "project has 6 contributing companies or organizations",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 3,
"reason": "dependency not pinned by hash detected -- score normalized to 3",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 7,
"reason": "3 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "ea7183479bbd1581280f33be6d5428ffd9c323c9",
"ran_at": "2026-07-21T16:52:08Z",
"aggregate_score": 3.2,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/nemanjan00/qrp",
"host": "github.com",
"name": "qrp",
"owner": "nemanjan00"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 55,
"inputs": {
"security": 32,
"vitality": 68,
"community": 32,
"governance": 42,
"engineering": 93
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "moderate",
"name": "Vitality",
"value": 68,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 55,
"inputs": {
"commits_last_year": 118,
"human_commit_share": 1,
"days_since_last_push": 4,
"active_weeks_last_year": 1
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 4 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 4
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "1/52 weeks with commits",
"points": 0.7,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 1
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "118 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 118
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 88,
"inputs": {
"releases_count": 21,
"latest_release_tag": "v0.7.0",
"releases_from_tags": true,
"days_since_latest_release": 4,
"mean_days_between_releases": 0.2
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "21 version tags (no GitHub releases)",
"points": 16.2,
"status": "partial",
"details": [
{
"code": "version_tags_no_releases",
"params": {
"count": 21
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 4 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 4
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~0.2 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 0.2
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "at_risk",
"name": "Community & Adoption",
"value": 32,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 0,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "0 stars",
"points": 0,
"status": "missed",
"details": [
{
"code": "stars",
"params": {
"count": 0
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
},
{
"key": "ecosystem_adoption",
"band": "moderate",
"name": "Ecosystem adoption (downloads)",
"note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"registry_dependents"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 57,
"inputs": {
"packages": [
"@nemanjan00/qrp"
],
"dependents": null,
"ecosystems": "npm",
"total_downloads": null,
"monthly_downloads": 2683
},
"components": [
{
"key": "monthly_downloads",
"name": "Monthly downloads",
"detail": "2,683 downloads/month across npm",
"points": 45.7,
"status": "partial",
"details": [
{
"code": "downloads_monthly",
"params": {
"count": 2683,
"ecosystems": "npm"
}
}
],
"max_points": 80
},
{
"key": "registry_dependents",
"name": "Registry dependents",
"detail": "not reported by this ecosystem",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_reported_by_this_ecosystem",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 42,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 20,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 6 contributing companies or organizations",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "critical",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution",
"pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 1,
"inputs": {
"merged_prs": 0,
"open_issues": 0,
"closed_issues": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 0
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "no issues or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_issues_or_data",
"params": {}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "no decided pull requests or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_decided_prs_or_data",
"params": {}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "moderate",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 62,
"inputs": {
"followers": 117,
"owner_type": "User",
"is_verified": null,
"owner_login": "nemanjan00",
"public_repos": 233,
"account_age_days": 5752
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "personal (user) account",
"points": 10,
"status": "partial",
"details": [
{
"code": "owner_personal",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": "not applicable to user accounts",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_applicable_to_user_accounts",
"params": {}
}
],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "117 followers of nemanjan00",
"points": 14.9,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 117,
"login": "nemanjan00"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "233 public repos, account ~15 yr old",
"points": 25,
"status": "met",
"details": [
{
"code": "public_repos",
"params": {
"count": 233
}
},
{
"code": "account_age_years",
"params": {
"years": 15
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"@nemanjan00/qrp"
],
"ecosystems": "npm",
"any_deprecated": false,
"min_days_since_publish": 4
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on npm",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "npm"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 4 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 4
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "18 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 18
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "excellent",
"name": "Engineering Quality",
"value": 93,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "excellent",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 88,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": true,
"has_linter_config": true,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "1 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 1
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": ".eslintrc.json",
"points": 16,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".eslintrc.json"
}
}
],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 6.4,
"status": "met",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "excellent",
"name": "Documentation",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"topics": [
"dashboard",
"declarative",
"dom",
"forms",
"framework",
"frontend",
"no-build",
"proxy",
"reactive",
"table",
"zero-dependency"
],
"has_wiki": true,
"homepage": "https://qrp.nemanja.top/",
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": "https://qrp.nemanja.top/",
"points": 15,
"status": "met",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": "11 topics",
"points": 10,
"status": "met",
"details": [
{
"code": "topics_count",
"params": {
"count": 11
}
}
],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "at_risk",
"name": "Security",
"value": 32,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Packaging, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"packaging",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 32,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 15,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 3,
"scorecard_aggregate": 3.2
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 6 contributing companies or organizations",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 3",
"points": 1.5,
"status": "partial",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "3 existing vulnerabilities detected",
"points": 5.2,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 3
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "moderate",
"name": "AI Readiness",
"value": 67,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.86,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 15489
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "86 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 86,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 57,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"package-lock.json"
],
"has_dockerfile": false,
"typed_language": false,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": true,
"typecheck_configs": [
"tsconfig.json"
],
"agent_commit_share": 0,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": ".eslintrc.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": ".eslintrc.json"
}
}
],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 100",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 3",
"points": 3,
"status": "partial",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "good",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 82,
"inputs": {
"primary_language": "JavaScript",
"largest_source_bytes": 46054,
"source_files_sampled": 84,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "JavaScript with type-check config (tsconfig.json)",
"points": 27,
"status": "partial",
"details": [
{
"code": "typecheck_config_language",
"params": {
"files": "tsconfig.json",
"language": "JavaScript"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/84 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 84,
"oversized": 0
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "at_risk",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": []
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"deps.dev does not index npm:@nemanjan00/qrp@0.7.0; advisories assessed against the repository dependency graph instead"
],
"report_type": "repository",
"generated_at": "2026-07-21T16:52:13.105613Z",
"schema_version": "0.23.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/n/nemanjan00/qrp.svg",
"full_name": "nemanjan00/qrp",
"license_state": "standard",
"license_spdx": "MIT"
}