Skip to content

release: prepare Core Reset 0.40.0-beta.1 - #617

Merged
mohanagy merged 25 commits into
nextfrom
agent/core-reset-beta-0.40.0-beta.1
Jul 28, 2026
Merged

release: prepare Core Reset 0.40.0-beta.1#617
mohanagy merged 25 commits into
nextfrom
agent/core-reset-beta-0.40.0-beta.1

Conversation

@mohanagy

@mohanagy mohanagy commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Outcome

Prepare the first Core Reset beta, @lubab/madar@0.40.0-beta.1, for the npm next channel without touching main.

Closes the release-preparation portion of #577. RFC #577 and the Core Reset milestone remain open until npm, the GitHub prerelease, MCP Registry metadata, and clean-install verification all complete.

Exact base and scope

  • Protected core-reset anchor: 5c9d1e2436932f7420169ea4ffa617c6bea4fbd0
  • Anchor tree: 35b68cd733e07b9306d52e2076a287269f8919eb
  • Exact PR head: 691b83abce9a1fc47c13f8ff9bc06741b5470c2a
  • Exact PR tree: c587bdbe811034e9873d2d81951b64aa1b9e5d04
  • Base: next
  • src/** changes: none
  • Runtime/development dependency changes: none

This candidate updates only governance truth, version/lock metadata, changelog and migration documentation, SBOM and MCP Registry metadata, release workflows, package-receipt verification, and their tests.

Capability Validation #610, #612, #614, #615, and #616 is cancelled and closed not planned. No campaign ran, no provider request or paid spend occurred, and no Native/Graphify/Madar result exists. This beta makes no comparative correctness, token, latency, cost, activation, retention, or external-user claim.

Release safety

  • npm version: 0.40.0-beta.1
  • npm dist-tag: next only
  • GitHub tag: v0.40.0-beta.1
  • GitHub Release: prerelease and not latest
  • npm publication: tag-triggered existing GitHub release workflow with an immediate exact-next-tip recheck, OIDC provenance, immutable registry verification, and npm-before-GitHub ordering; no token or no-provenance fallback
  • MCP Registry publication: separate, only after npm confirms the exact public package
  • Stable 0.40.0, npm latest, and main: not authorized

The current next-only history commit has the same tree as the shared merge base, so this PR has no content conflict with the Core Reset line.

Local verification

  • npm ci: passed; 0 vulnerabilities
  • release hygiene: passed
  • Registry validation: passed
  • typecheck: passed
  • production and evaluation builds: passed
  • targeted governance/release tests: 31 passed
  • full single-worker suite: 74 files / 624 tests passed
  • Core Reset baseline suite: 5 passed
  • packed checkout/install/CLI/MCP parity: passed
  • package isolation: passed
  • packed manual smoke: version, generation, query, Claude install, and uninstall passed with zero repository changes
  • npm provenance dry-run: passed
  • git diff --check: passed

Fresh package receipt:

  • 102 files
  • 160,118 packed bytes
  • 638,445 unpacked bytes
  • npm shasum 5811e58e02799d103ad12b7220c31e6a7244043c
  • SHA-256 390ba73ae215caea37a3403d7963f709997ac86d462e8e3dedfed8a710c7fa40

Merge gate

Do not merge until all six exact-head CI jobs pass, independent exact-head review finds no blocker, and zero review threads remain. CodeRabbit runs on a non-default base here; its actual result or skip must be recorded honestly.

Summary by CodeRabbit

  • New Features

    • Introduced the 0.40.0-beta.1 release with a canonical JavaScript/TypeScript code graph and authenticated evidence retrieval.
    • Added a streamlined CLI workflow for generating indexes, querying evidence, checking status, and installing MCP integrations.
    • Added MCP support with a single bounded retrieve tool for evidence, relationships, and clear result boundaries.
    • Added Claude Code and Codex installation, inspection, and uninstall support.
  • Documentation

    • Added migration guidance from 0.32.x and refreshed setup, compatibility, security, roadmap, and CLI/MCP documentation.
    • Clarified supported languages, evidence limits, and retired legacy commands and integrations.
  • Bug Fixes

    • Improved graph freshness, integrity validation, concurrency handling, crash recovery, and packed-runtime parity checks.

mohanagy added 24 commits July 19, 2026 22:29
* docs: establish Core Reset governance

* test: strengthen Core Reset governance

* docs: accept Core Reset RFC
* test: freeze Core Reset baseline contract

* test: harden Core Reset measurement integrity

* test: record Core Reset baseline evidence

* docs: clarify baseline measurement provenance

* docs: address baseline review findings
…583)

* refactor: replace graph core with deterministic directed multigraph

* test: normalize core reset metrics on Windows

* test: make core reset LOC checks platform-neutral

* fix: address directed multigraph review findings

* fix: validate freshness against exact artifact bytes
Record the passed graph phase, its final evidence, and the canonical TypeScript index as the only Ready successor.
* feat: replace SPI with canonical TypeScript index

* fix: address canonical index review findings
Record the completed canonical index evidence, the owner-approved CodeRabbit rate-limit exception, and the combined legacy/non-code deletion as the only Ready work item.
* docs: activate legacy extraction deletion

* test: enforce deletion activation inventory

* style: align governance test types

* chore: update vulnerable fast-uri transitive
Deletes the retired extraction architecture and makes the canonical TypeScript/JavaScript index the sole generation path. Preserves fail-closed predecessor gates, freshness/worktree behavior, and package/test coverage. Governance closure remains tracked in #588.
Records the completed legacy/non-code deletion receipts, leaves the final package gate open, and makes generation-and-incremental Ready but not active. Closes the phase governance without changing production source.
Activates the owner-approved #592 governance contract without runtime or package changes.
* test: record failed incremental index experiment

* refactor: simplify index refresh to full reconciliation

* refactor: replace incremental refresh with full reconcile

* docs: record full reconcile acceptance evidence

* fix: canonicalize Windows index paths

* docs: reseal incremental acceptance evidence

* test: isolate incremental policy reconciles
Closes #592. Records the final generation/reconciliation evidence and leaves evidence-path query Ready but not active.
Freeze the owner-approved deletion, replacement, held-out, correctness, performance, package, and review contracts for the evidence-path query phase. This governance-only activation changes no production or released behavior.
…ence paths (#600)

* test(core-reset): replace held-out evidence governance

* refactor(core-reset): replace evidence query stack

* feat(core-reset): implement evidence-path query

* fix(eval): canonicalize held-out path arguments

* test(core-reset): record held-out evidence

* fix(query): preserve explicit relation paths

* test(core-reset): refresh held-out evidence

* perf(query): avoid redundant structural scans

* test(core-reset): record performance evidence

* test(core-reset): refresh optimized held-out evidence

* test(core-reset): record phase inventory

* fix(query): preserve exact declaration targets

* test(core-reset): refresh final query evidence

* fix(query): close evidence path acceptance gates

* docs(core-reset): bind final evidence receipts

* test(package): require successful retrieval parity

* fix(query): make evidence boundaries platform-stable

* chore(deps): update transitive postcss security fix

* fix(query): bound retrieve question work

* docs(core-reset): bind final portable evidence receipts
Activate the exact owner-approved #602 Thin Delivery governance contract on core-reset.

Governance-only activation: zero production/package delta. All six exact-head CI jobs passed, independent review found no blocker, zero review threads remained, and CodeRabbit explicitly skipped the non-default base.
* feat(core-reset): implement Thin Delivery contract

* fix(ci): escape benchmark MCP paths
Governance-only activation of the exact owner-approved #606 contract against core-reset. No production code, package, dependency, publication, release, Registry, main-branch, or Capability Validation change.
Exact approved governance-only Capability Validation v2 activation. Offline implementation remains limited to the accepted contract; campaign/provider execution remains unauthorized.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements the accepted Core Reset (RFC #577): a deletion-led rewrite replacing Madar's legacy extraction/graph/pack/CLI/MCP stack with a directed multigraph domain model, canonical TypeScript indexing, a deterministic retrieve application/MCP surface, thin CLI adapters, isolated evaluation tooling under tools/eval, a rewritten test suite, and updated release/CI governance and documentation for 0.40.0-beta.1.

Changes

Core Reset Implementation

Layer / File(s) Summary
Repository governance and templates
.gitattributes, .github/ISSUE_TEMPLATE/*, .github/pull_request_template.md, .github/repo-metadata.json, .gitignore, CONTRIBUTING.md
Adds Core Reset issue/PR templates and governance checklist, updated repo metadata, and contributing guidance.
CI, release, and build/package configuration
.github/workflows/*, .github/scripts/*, package.json, package-lock.json, sbom.cdx.json, tsconfig*.json, vitest.config.ts, docs/release.md
Rewrites CI/release workflows and verification scripts, bumps package/lockfile/SBOM to 0.40.0-beta.1, and adds isolated eval build config.
Domain and application layer
src/domain/**, src/application/**, src/core/provenance/types.ts, src/contracts/runtime-proof.ts
Introduces the directed-multigraph model, canonical artifact serialization, index build-state, query ranking/traversal/slicing, and generate/update/retrieve application services.
Thin CLI/MCP adapters and infrastructure
src/adapters/**, src/infrastructure/watch-index.ts, src/shared/*, src/pipeline/extract/python-rationale.ts
Implements the new CLI, MCP server/protocol, filesystem index-store/source-catalog, and TypeScript compiler-backed canonical indexer with framework detectors.
Rewritten test suite
tests/**
Replaces obsolete tests with new fixtures and unit tests covering the new domain/application/adapter architecture.
Evaluation tooling isolation
tools/eval/**
Moves benchmark/eval tooling and Core Reset contracts/evaluators into a dev-only, production-isolated location.
Documentation and examples rewrite
README.md, CHANGELOG.md, docs/**, examples/**
Rewrites README, roadmap, scorecard, threat model, migration guide, and examples for the new one-tool retrieval product.

Estimated code review effort: 5 (Critical) | ~180+ minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client as MCP Client
  participant Server as McpServer
  participant Runtime as McpRuntime/WatchIndex
  participant App as retrieveContext (application)
  participant Graph as KnowledgeGraph (graph.json)

  Client->>Server: initialize / tools-list
  Server->>Runtime: start reconciler (first ready)
  Runtime->>Graph: generateIndex / updateIndex
  Graph-->>Runtime: accepted build_id
  Client->>Server: tools/call retrieve(question, budget)
  Server->>Runtime: loadQueryIndex()
  Runtime-->>Server: ReadyQueryIndex or unavailable
  Server->>App: retrieveContext(index, request)
  App->>Graph: authenticate nodes/edges via source hashes
  App-->>Server: RetrieveContextResult (evidence/boundaries)
  Server-->>Client: JSON-RPC result (madar.retrieve envelope)
Loading

Possibly related issues

Suggested labels: core-reset

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the Core Reset beta release prep.
Description check ✅ Passed It covers the release outcome, scope, safety rules, verification, and issue linkage, with the template content mostly present in prose.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/core-reset-beta-0.40.0-beta.1

Comment @coderabbitai help to get the list of available commands.

@mohanagy
mohanagy force-pushed the agent/core-reset-beta-0.40.0-beta.1 branch from 07ac630 to 691b83a Compare July 28, 2026 17:56

@mohanagy mohanagy left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent exact-head review — no blocker found.

Reviewed exact head 691b83abce9a1fc47c13f8ff9bc06741b5470c2a, tree c587bdbe811034e9873d2d81951b64aa1b9e5d04, against protected Core Reset anchor 5c9d1e2436932f7420169ea4ffa617c6bea4fbd0 and PR base next.

The review verified that the original three blockers are resolved: publication uses the existing tag-triggered release.yml; the lock-only SBOM has 105/105 lock-backed components with a regression guard; and Capability Validation is explicitly historical/stopped with all unused authority revoked. The release workflow binds checkout, remote next, and the peeled remote release tag to GITHUB_SHA during initial validation, at publication-step entry, immediately before irreversible npm publication, and again before GitHub prerelease creation. It publishes npm next with tokenless OIDC provenance before creating the prerelease, verifies exact shasum/integrity, dist-tags, provenance, signatures, authoritative remote tag, prerelease state, and unchanged latest, and has no token/no-provenance fallback. No src/** or dependency change exists. No blocker was found. CI remains a separate exact-head merge gate.

@mohanagy

Copy link
Copy Markdown
Owner Author

Pre-merge CodeRabbit disposition for exact head 691b83abce9a1fc47c13f8ff9bc06741b5470c2a: CodeRabbit has not completed a review and is not counted as review evidence. Its check has remained PENDING since 2026-07-28T17:56:17Z; the live comment says review in progress and shows that the non-default next base caused it to process the full 661-file history comparison from aac697257dd8527a5bdee73d29723892129de7e7, rather than only the 21-file release candidate. It has submitted no review and opened zero threads. This is recorded honestly as an incomplete/non-default-base disposition, not a pass or skip. The mandatory independent exact-head review separately found no blocker at #617 (review). All six exact-head CI jobs in run https://github.com/mohanagy/madar/actions/runs/30385143299 are green, and the live review-thread count is zero.

@mohanagy
mohanagy merged commit 522d138 into next Jul 28, 2026
6 of 7 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tools/eval/lib/infrastructure/benchmark/suite.ts (1)

853-868: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Recursive copy publishes every compare artifact; only report.json is scrubbed.

cpSync copies the whole compare output root into the published raw/ tree, then just overwrites report.json with the share-safe body. Any other non-share-safe artifact produced by executeNativeAgentCompare (transcripts, raw provider output) is published as-is. Consider copying an explicit allowlist of artifact names instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/eval/lib/infrastructure/benchmark/suite.ts` around lines 853 - 868, The
copyReportArtifacts function currently publishes every compare artifact and only
sanitizes report.json. Replace the recursive directory copy with an explicit
allowlist of share-safe artifact names, copying only those entries into
copiedRoot; continue validating and writing report.json from
report.share-safe.json, and do not publish transcripts or raw provider output.
🟠 Major comments (25)
.github/scripts/verify-packed-retrieval-parity.mjs-60-85 (1)

60-85: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Byte-exact tarball identity is pinned in two places and assumes a reproducible npm pack across three different npm installs. The recorded shasum/integrity/SHA-256 values are produced by gzip plus a specific npm version; .github/workflows/release.yml pins npm@12.0.1 (line 36) while .github/workflows/ci.yml runs npm run verify:pack-parity with whatever npm the runner image ships, and the receipt in docs/core-reset/removal-manifest.yml was measured on a maintainer machine. Any of those drifting turns a correct change into a hard release/CI failure.

  • .github/scripts/verify-packed-retrieval-parity.mjs#L60-L85: keep file-count and the budget maxima as the CI-side gate, and move the exact npm_shasum / npm_integrity / npm_artifact_sha256 equality behind a flag that only the pinned release workflow sets.
  • .github/workflows/release.yml#L166-L167: derive EXPECTED_SHASUM / EXPECTED_INTEGRITY from the receipt in docs/core-reset/removal-manifest.yml (single source of truth) instead of duplicating literals here, so a re-measured artifact only has to be updated once.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/verify-packed-retrieval-parity.mjs around lines 60 - 85,
Keep the file-count and budget checks unconditional in
verify-packed-retrieval-parity.mjs, but gate the npm_shasum, npm_integrity, and
npm_artifact_sha256 equality checks behind an explicit flag enabled only by the
pinned release workflow. In .github/workflows/release.yml, derive
EXPECTED_SHASUM and EXPECTED_INTEGRITY from docs/core-reset/removal-manifest.yml
instead of duplicating literals, while preserving the existing release
verification behavior.
.github/scripts/verify-packed-retrieval-parity.mjs-469-473 (1)

469-473: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Timing-dependent assertion is a flake source in a required gate.

The check requires the ping (id 702) response to arrive and the queued retrieve (id 701) to still be absent within a 5s window. On a fast runner (or if reconcile of the 300-file workspace completes quickly), 701 can land before the poll loop observes 702, failing CI for a correct runtime. Conversely a slow runner never sees 702 in 5s.

Assert responsiveness by ordering rather than absence — e.g., record the arrival index of 702 vs 701 in the accumulated stream and require 702 to precede 701 — and derive the deadline from requestWaitMs instead of a fixed 5s.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/verify-packed-retrieval-parity.mjs around lines 469 - 473,
Update the responsiveness assertion in the packed MCP stdio verification flow to
compare the arrival positions of responses 702 and 701 in the accumulated
stream, requiring 702 to precede 701 rather than requiring 701 to remain absent
during polling. Use a deadline derived from requestWaitMs instead of the fixed
5-second timeout, while preserving failure handling when 702 is not received or
arrives after 701.
.github/scripts/ci-eval-regression.mjs-30-37 (1)

30-37: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Non-finite metrics silently pass the gate.

If report drifts (renamed/missing avg_recall, mrr, avg_snippet_coverage), the comparisons become NaN < 90false and CI reports success with no enforcement. Validate the metrics are finite before comparing.

🛡️ Proposed guard
 const recall = report.avg_recall * 100
 const snippetCoverage = report.avg_snippet_coverage * 100
+for (const [label, value] of Object.entries({ recall, mrr: report.mrr, snippetCoverage })) {
+  if (!Number.isFinite(value)) {
+    throw new Error(`eval report metric ${label} is not a finite number: ${value}`)
+  }
+}
 if (recall < 90 || report.mrr < 0.95 || snippetCoverage < 95) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/ci-eval-regression.mjs around lines 30 - 37, Update the
threshold validation around recall, report.mrr, and snippetCoverage to reject
any non-finite metric values before performing comparisons. Ensure missing,
renamed, NaN, or infinite values throw an evaluation-threshold error rather than
allowing CI to pass, while preserving the existing threshold checks and error
reporting for valid metrics.
tools/eval/core-reset/schemas/capability-validation-receipt.schema.json-158-158 (1)

158-158: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Update the hardcoded source identities in campaignLock and campaignLockPass
The implementation_source_hashes entries still point to tools/eval/core-reset/capability-validation.mjs, tools/eval/lib/capability-validation/contract.ts, tools/eval/lib/capability-validation/report.ts, and tests/unit/capability-validation-contract.test.ts, but the repo only contains tools/eval/core-reset/contract-validation.mjs. If these paths stay as-is, receipts built from this schema will fail validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/eval/core-reset/schemas/capability-validation-receipt.schema.json` at
line 158, Update the implementation_source_hashes path constants in both
campaignLock and campaignLockPass to reference the repository’s actual
tools/eval/core-reset/contract-validation.mjs source identity, removing the
stale capability-validation entry paths while preserving the existing identity
ordering and hash validation structure.
tools/eval/core-reset/evidence-path-held-out.mjs-1337-1344 (1)

1337-1344: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use --permission here. --experimental-permission is rejected by Node v24.15.0, so held-out children abort before executing and runContainedNode fails immediately.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/eval/core-reset/evidence-path-held-out.mjs` around lines 1337 - 1344,
Update the nodeArguments construction in runContainedNode to pass Node’s
supported --permission flag instead of --experimental-permission, while
preserving the existing read/write permission arguments and entry-point
ordering.
tools/eval/core-reset/schemas/capability-validation-receipt-v2.schema.json-404-429 (1)

404-429: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

builder_path points at a file that isn't present in this tree, so v2 receipts won't satisfy this schema until that builder lands.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/eval/core-reset/schemas/capability-validation-receipt-v2.schema.json`
around lines 404 - 429, The builder_path constant in the receipt schema
references a file absent from the tree; update it to the actual existing v2
receipt-builder location, while preserving the required builder-path validation
for valid receipts.
tools/eval/lib/shared/shell.ts-25-42 (1)

25-42: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Login shell is the wrong default for measured runs.

options.login === false ? '-c' : '-lc' makes -lc the default, and the only caller (compare.ts line 235) passes no options. A login shell sources the operator's profile/rc files, so PATH, proxies, version managers, and agent configuration leak into every measured arm — directly at odds with the scrubbed-environment requirements the surrounding contracts impose, and it makes results host-dependent. Invert the polarity so login is opt-in.

🛠️ Proposed fix
   return {
     file: '/bin/sh',
-    args: [options.login === false ? '-c' : '-lc', command],
+    args: [options.login === true ? '-lc' : '-c', command],
     useProcessGroup: true,
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/eval/lib/shared/shell.ts` around lines 25 - 42, Update
resolveShellCommand to make the non-login '-c' mode the default for non-Windows
platforms, enabling '-lc' only when options.login is explicitly true. Preserve
the existing Windows command handling and process-group behavior.
tools/eval/lib/infrastructure/compare.ts-231-294 (1)

231-294: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Timeout leaves the real agent process running.

resolveShellCommand returns useProcessGroup: true, but spawn here is not detached, so the abort on timeout terminates only /bin/sh. The agent process it launched survives as an orphan — it keeps burning provider tokens and CPU and may still write answerFile after the arm is recorded as timed_out. Honour useProcessGroup and kill the group.

🛠️ Proposed fix
     const command = resolveShellCommand(input.command)
     const child = spawn(command.file, command.args, {
       cwd: input.cwd,
       shell: false,
+      detached: command.useProcessGroup,
       signal: input.signal,
       stdio: ['ignore', 'pipe', 'pipe'],
     })
+    if (command.useProcessGroup && child.pid !== undefined) {
+      input.signal?.addEventListener('abort', () => {
+        try {
+          process.kill(-child.pid!, 'SIGKILL')
+        } catch {
+          /* group already gone */
+        }
+      }, { once: true })
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/eval/lib/infrastructure/compare.ts` around lines 231 - 294, Update
defaultNativeAgentRunner to honor the useProcessGroup value returned by
resolveShellCommand: spawn the command detached when requested, and ensure
abort/timeout handling in runNativeArm terminates the entire process group
rather than only the shell. Preserve normal process cleanup and existing result
reporting.
examples/quick-benchmark.sh-15-18 (1)

15-18: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Install the authorized beta channel explicitly.

Without @next, npm resolves its default channel, so this script can install a different stable or older CLI contract than the 0.40.0-beta.1 workflow being documented.

Proposed fix
-  echo "Install Madar first: npm install -g `@lubab/madar`"
+  echo "Install Madar first: npm install -g `@lubab/madar`@next"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/quick-benchmark.sh` around lines 15 - 18, Update the missing-madar
installation guidance in the quick benchmark script to explicitly install the
authorized beta channel by appending `@next` to the `@lubab/madar` package
specifier. Keep the existing command-not-found check and exit behavior
unchanged.
docs/mcp-registry/server.json-19-28 (1)

19-28: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Make the npx launch non-interactive. Add runtimeArguments: [{ "type": "named", "name": "--yes" }]; otherwise uncached installs can prompt and stall MCP hosts without stdin.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/mcp-registry/server.json` around lines 19 - 28, Add a runtimeArguments
entry to the server configuration alongside the existing runtimeHint and
transport settings, using a named --yes argument so npx launches
non-interactively. Preserve the existing packageArguments configuration.
docs/benchmarks/suite/holdouts/tasks.json-7-8 (1)

7-8: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not silently remove a frozen holdout prompt.

This changes the evaluator workload and can invalidate existing receipts and comparability. Restore the prompt, or amend the evaluation contract and regenerate every dependent receipt before merging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/benchmarks/suite/holdouts/tasks.json` around lines 7 - 8, Restore the
frozen “holdout-order-service” prompt in the prompts configuration, preserving
its existing text and key. Do not remove or alter the evaluator workload unless
the evaluation contract is explicitly amended and all dependent receipts are
regenerated.
docs/roadmap.md-91-96 (1)

91-96: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Disambiguate the <80 MiB RSS gate.

The gate reports metrics for both commands, while the recorded initialize/tools-list maximum RSS is 208,977,920 bytes, well above 80 MiB. If the cap applies to both commands, the evidence fails; if it applies only to madar --version, scope the requirement explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/roadmap.md` around lines 91 - 96, Clarify the RSS requirement in the
roadmap entry so the <80 MiB cap explicitly applies only to madar --version, or
revise the recorded initialize/tools-list result and acceptance criteria if both
commands must satisfy it. Keep the metrics and claims consistent with the chosen
scope.
docs/roadmap.md-134-136 (1)

134-136: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Record the required publication ordering and verification gates.

The release sequence must explicitly require OIDC provenance, immutable package verification, exact next-tip confirmation, npm-before-GitHub ordering, and Registry publication only after exact package confirmation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/roadmap.md` around lines 134 - 136, Update the release sequence in the
roadmap to explicitly require OIDC provenance, immutable verification of the
published package, confirmation that the reviewed commit is the exact tip of
next, npm publication before creating the GitHub prerelease, and MCP Registry
publication only after confirming the exact package. Preserve the existing beta
scope and all listed validation gates.
docs/migrations/0.40.0-beta.1.md-78-80 (1)

78-80: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Align the installer byte-mutation contract across all documentation.

The documents promise zero repository-byte changes for uninstall while also documenting cleanup of repository-local, Madar-owned legacy artifacts. Make the exception explicit everywhere:

  • docs/migrations/0.40.0-beta.1.md#L78-L80: distinguish normal byte-neutral operations from legacy cleanup.
  • docs/reference/cli-and-mcp.md#L110-L124: qualify the uninstall guarantee.
  • docs/roadmap.md#L90-L90: clarify the thin-delivery contract.
  • docs/security/mcp-threat-model.md#L31-L35: state that exact owned-artifact cleanup is the limited exception.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/migrations/0.40.0-beta.1.md` around lines 78 - 80, Align the installer
byte-mutation contract across all documented sites: in
docs/migrations/0.40.0-beta.1.md lines 78-80, distinguish normal byte-neutral
install, reinstall, and uninstall operations from exact Madar-owned legacy
cleanup; in docs/reference/cli-and-mcp.md lines 110-124, qualify the uninstall
guarantee with that exception; in docs/roadmap.md line 90, clarify the
thin-delivery contract similarly; and in docs/security/mcp-threat-model.md lines
31-35, state that exact owned-artifact cleanup is the sole limited exception.
docs/share-safe-dashboard-decision.md-8-8 (1)

8-8: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not promise that report.share-safe.json hides workstation paths.

Share-safe artifacts are documented elsewhere as best-effort redactions that must be reviewed before publication. Qualify this sentence to avoid a false privacy guarantee.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/share-safe-dashboard-decision.md` at line 8, Update the description of
report.share-safe.json in the documentation to state that it provides
best-effort redaction only, rather than guaranteeing workstation paths are
hidden. Direct readers to review the artifact before sharing or publication,
while preserving its purpose for benchmark and compare receipts.
docs/benchmarks/suite/isolation/environment.json-9-9 (1)

9-9: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Recompute project_claude_md_hash from docs/benchmarks/suite/isolation/.claude/CLAUDE.md. The stored value doesn’t match the file’s current SHA-256 (sha256:0cf98a0a8f9c27017a0bebc7b017fc17518d9103c62ca384da20b2776b0aade7 vs sha256:729ce56a7c59791da8720f3d30d9a580a12d0115072afbc9815e8296f6b8b386), so the isolation attestation is stale.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/benchmarks/suite/isolation/environment.json` at line 9, Update the
project_claude_md_hash value in environment.json to the current SHA-256 of the
isolation .claude/CLAUDE.md file:
sha256:0cf98a0a8f9c27017a0bebc7b017fc17518d9103c62ca384da20b2776b0aade7.
docs/claims-and-evidence.md-17-21 (1)

17-21: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Anchor historical comparisons to exact receipts or remove them.

Lines 17-21 still publish comparative tool-call, input-token, latency, and cost results, but provide no dated receipt links or repository/task conditions. Either link the immutable historical artifacts and label this explicitly as archived, non-beta evidence, or remove the comparison to preserve the PR’s no-comparative-claims boundary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/claims-and-evidence.md` around lines 17 - 21, Update the historical
comparison in the surrounding claims-and-evidence section to either link
immutable, dated receipts that document the repository and task conditions and
label the results as archived non-beta evidence, or remove the comparative
tool-call, input-token, latency, and cost claims entirely. Preserve the
no-comparative-claims boundary if verifiable artifacts are unavailable.
src/domain/query/slice.ts-100-113 (1)

100-113: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Self-referential token count can fail to stabilize and the fallback is very expensive.

serialized_tokens is embedded in the very payload being tokenized, so f(n) = countTokens(serialize(result(n))) can oscillate between two values across a digit boundary (e.g. 999 ↔ 1000), exhausting the 16 passes. The fallback then performs up to 10,001 full canonical serializations + tokenizations on the request path, and — because resultWithTokenCount is also called on the pre-budget cappedResult (line 183), whose count can exceed 10,000 tokens — it can miss the fixed point entirely and throw Unable to stabilize retrieve serialized token count, failing the whole retrieve call.

Consider removing the self-reference instead of searching for it: either exclude metrics.serialized_tokens from the tokenized payload, or serialize it as a fixed-width value so the count is digit-length invariant. If iteration is kept, detect the 2-cycle and pick the larger of the oscillating pair rather than scanning a bounded range.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/domain/query/slice.ts` around lines 100 - 113, The resultWithTokenCount
stabilization logic in src/domain/query/slice.ts must avoid the expensive
bounded fixed-point scan and failure for oscillating or large token counts.
Prefer removing the self-reference by excluding metrics.serialized_tokens from
the tokenized payload or encoding it at fixed width; if iteration remains,
detect a two-value cycle and return a result using the larger oscillating count,
preserving correct behavior for pre-budget cappedResult.
tests/unit/review-express-regressions.test.ts-44-55 (1)

44-55: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use .size instead of toHaveLength on these Set checks.
Set doesn’t have a length property, so these uniqueness assertions should read .size directly.

🐛 Proposed fix
     expect(middleware).toHaveLength(2)
-    expect(new Set(middleware.map(([id]) => id))).toHaveLength(2)
+    expect(new Set(middleware.map(([id]) => id)).size).toBe(2)
@@
     expect(routeEdges).toHaveLength(2)
-    expect(new Set(routeEdges.map((edge) => edge.toId))).toHaveLength(2)
+    expect(new Set(routeEdges.map((edge) => edge.toId)).size).toBe(2)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/review-express-regressions.test.ts` around lines 44 - 55, Update
the uniqueness assertions in the test block to compare each Set’s `.size` with
the expected count instead of using `toHaveLength`. Apply this to the Sets
created from `middleware` IDs and `routeEdges` destination IDs, while leaving
the array length assertions unchanged.
src/shared/discovery-safety.ts-286-287 (1)

286-287: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Dropping the artifact size guard makes this read unbounded.

The previous implementation capped the graph artifact bytes before parsing; loadGraphArtifact now reads and fully parses the artifact just to pull graph.discovery_safety. On a very large (or untrusted) graph.json this becomes an unbounded memory/CPU cost on every cache miss, and the cache miss path is triggered by any touch of the file. Consider keeping a byte ceiling, or reusing an artifact already loaded by the caller.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/discovery-safety.ts` around lines 286 - 287, Restore a bounded
read in the discovery metadata cache-miss path instead of calling
loadGraphArtifact, which fully loads and parses the artifact. Update the logic
around parseDiscoverySafetyMetadata and discoveryMetadataCache.set to extract
graph.discovery_safety from a size-limited artifact read, or reuse an already
loaded artifact when available, while preserving cache behavior.
src/domain/query/rank.ts-585-590 (1)

585-590: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

fields[0] is not reliably the label field.

buildCorpus (Lines 168-181) drops any field whose value produces no tokens, so when a node has no label the first element becomes qualified_name (or framework/metadata/node_kind). labelMatches, exactLabelMatches, and labelPrecision then silently score against the wrong field. Positional lookup by weight won't help either, since label and qualifiedName share weight 12.

🐛 Proposed fix: carry the label tokens explicitly on the corpus node
 interface RankCorpusNode {
   id: string; documentKey: string; attributes: GraphAttributes; fields: readonly RankField[]
+  labelTokens: ReadonlySet<string>
   tokens: ReadonlySet<string>; pathTokens: ReadonlySet<string>; sourceFile: string
-  const labelTokens = candidate.node.fields[0]?.tokens ?? new Set<string>()
+  const labelTokens = candidate.node.labelTokens

and in buildCorpus, set labelTokens: new Set(lexicalTokens(stringAttribute(attributes, 'label'))).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/domain/query/rank.ts` around lines 585 - 590, Stop deriving labelTokens
from candidate.node.fields[0], since fields are omitted when empty and their
order is not reliable. Extend the corpus node produced by buildCorpus with an
explicit labelTokens field populated from the label attribute via
stringAttribute and lexicalTokens, then update the ranking logic around
labelMatches, exactLabelMatches, and labelPrecision to use that field while
preserving the empty-set fallback behavior.
tests/unit/canonical-index-framework-regressions.test.ts-121-121 (1)

121-121: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use .size for the Set cardinality check

toHaveLength only reads .length, so this assertion won’t check the 16 distinct storage operations. Use .size instead:
expect(new Set(operations.map((node) => node.storage_operation)).size).toBe(16)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/canonical-index-framework-regressions.test.ts` at line 121, Update
the distinct storage-operation assertion in the canonical index regression test
to read the Set’s size and compare it with 16, rather than using toHaveLength on
the Set.
src/adapters/typescript/framework-express.ts-357-364 (1)

357-364: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

express.Router() via a default import is not detected.

The property-access branch only consults namespaceAlias, so the most common Express router idiom — import express from 'express'; const r = express.Router() — never yields an express_router role, and every route registered on r is dropped.

🐛 Proposed fix: also accept members on the default-import binding
   if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression) && ts.isIdentifier(callee.name)) {
     const namespaceName = callee.expression.text
     const memberName = callee.name.text
-    if (bindings.namespaceAlias.has(namespaceName)) {
+    if (bindings.namespaceAlias.has(namespaceName) || bindings.appFactory.has(namespaceName)) {
       if (memberName === 'Router') return 'express_router'
       if (memberName === 'default') return 'express_app'
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adapters/typescript/framework-express.ts` around lines 357 - 364, Update
the property-access handling around the namespaceAlias check to also recognize
when callee.expression matches the default-import binding for Express. Return
express_router for the Router member and preserve express_app handling for
default, ensuring express.Router() through a default import is classified
correctly.
src/adapters/typescript/framework-express.ts-149-163 (1)

149-163: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Mount prefix can be applied more than once to the same handler symbol.

The loop rewrites handler.framework_metadata.route_path per matching edge, but a single handler symbol can be the target of multiple route_handler edges from the same router (e.g. router.get('/a', handler) and router.post('/a', handler)) or from several mounted routers. Each pass re-prefixes the already-prefixed value, producing paths like /api/api/a.

🐛 Proposed fix: prefix each handler at most once
+  const prefixed = new Set<string>()
   for (const edge of opts.edges) {
     if (edge.kind !== 'route_handler') continue
     const router = routerById.get(edge.from)
     if (!router) continue
     const mountPath = router.framework_metadata?.mount_path
     if (typeof mountPath !== 'string' || mountPath.length === 0) continue
     const handler = routeHandlerById.get(edge.to)
     if (!handler) continue
+    if (prefixed.has(handler.id)) continue
     const existingPath = handler.framework_metadata?.route_path
     if (typeof existingPath !== 'string') continue
+    prefixed.add(handler.id)
     handler.framework_metadata = {
       ...(handler.framework_metadata ?? {}),
       route_path: joinRoutePath(mountPath, existingPath),
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adapters/typescript/framework-express.ts` around lines 149 - 163, Update
the route-handler edge loop so each handler symbol’s route path is prefixed at
most once, even when multiple edges target it or multiple routers mount it. Use
the original unprefixed route path for each handler, track processed handlers or
otherwise guard against repeated updates, and preserve the existing mount-path
validation and joinRoutePath behavior.
src/infrastructure/watch-index.ts-26-35 (1)

26-35: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Watcher ignore filter doesn't match nested node_modules/.git/out directories.

The regex /^(?:out|node_modules|\.git)(?:\/|$)/ is anchored to the start of the path, so it only filters events at the watched root. With recursive fs.watch, filename is reported relative to the watched root, so any change inside a nested node_modules (e.g. packages/app/node_modules/..., a layout this project explicitly supports per the canonical-index monorepo fixtures) is not filtered and triggers changed(), causing debounced full reconciliation storms during ordinary operations like npm install in a sub-package.

🐛 Proposed fix: match nested occurrences too
-    const watcher = watchFilesystem(root, { recursive: true }, (_event, filename) => {
-      if (/^(?:out|node_modules|\.git)(?:\/|$)/.test(filename?.toString().replaceAll('\\', '/') ?? '')) return
+    const watcher = watchFilesystem(root, { recursive: true }, (_event, filename) => {
+      if (/(?:^|\/)(?:out|node_modules|\.git)(?:\/|$)/.test(filename?.toString().replaceAll('\\', '/') ?? '')) return
       changed()
     })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infrastructure/watch-index.ts` around lines 26 - 35, Update the ignore
filter in defaultEventSource so out, node_modules, and .git directories are
ignored wherever they occur in the recursive filename path, including nested
package directories. Normalize path separators as currently done and preserve
changed() for non-ignored events.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant