mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-09-14 14:01:28 +08:00
docs/x-gateway-github-style-metadata
284 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2629de628b |
chore(release): 3.39.3 -> 3.40.0
Ship cross-host federation (agentbbs) + claims. New MCP tools:
federation_bbs_{identity,peer_add,peers,serve,register,publish,sync,watch}.
Signed Ed25519 envelopes, registry-anchored pinning, HTTP pull transport.
Includes the memory-search recall fix (#3252).
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67
|
||
|
|
e855ae2e4e |
chore(release): 3.39.2 -> 3.39.3
Ships #3250: the agentbbs MCP tools gated on `await import('agentbbs')`, but the published package is a CLI-only launcher with no importable entry point, so all four federation_bbs_* tools reported degraded regardless of install state. Replaced with a subprocess probe. Includes the follow-up hardening: the probe's shell is now gated to win32 instead of always on. The probed binary comes from AGENTBBS_BIN, and under a shell that argument is command-interpreted, so a crafted value executed a trailing command (verified locally). POSIX now spawns without a shell. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013u4pmL9ZUAXb6usVQgNo67 |
||
|
|
498a238799 |
fix(security): make the fast-uri CVE fix actually reach shipped packages (#3222) — 3.39.2 (#3247)
* fix(security): make the fast-uri CVE fix actually reach shipped packages (#3222) 3.39.1 bumped fast-uri only in the ROOT package.json. Post-publish validation caught that this never reached users: a fresh `npm install ruflo@3.39.1` still resolved fast-uri@3.1.5, squarely inside the advisory range (GHSA-5jgf-p345-68v8, high, CVSS 7.5, >=3.1.3 <3.1.6). Root cause: v3/@claude-flow/cli/package.json carried its own hard pin "fast-uri": "3.1.5" in dependencies, and that is the package that actually ships. The root bump did not override it -- the #2112 lesson recorded in CLAUDE.md, that root overrides do NOT propagate to the published ruflo wrapper, applies to the CLI package too. - v3/@claude-flow/cli: fast-uri 3.1.5 -> ^3.1.6 (the shipping dependency) - ruflo: add "fast-uri": ">=3.1.6" override so the wrapper cannot regress independently of the CLI Verified by fresh-installing the published tarball rather than trusting the lockfile: that is what surfaced the gap in the first place. Refs #3222, #2112 Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01JJnDvpYYk2rTvjkudQUoCk * fix(ci): refresh v3 pnpm lockfile for the fast-uri bump The 3.39.2 fast-uri change touched v3/@claude-flow/cli/package.json but only the npm lockfile was regenerated. v3/ is a separate pnpm workspace and CI runs pnpm install --frozen-lockfile with working-directory: v3, which rejected the mismatch (ERR_PNPM_OUTDATED_LOCKFILE) and cascaded into 34 failing checks -- every one an install failure, not a real regression. Diff is 6 lines, fast-uri only: specifier 3.1.5 -> ^3.1.6, resolved 3.1.7. Verified pnpm install --frozen-lockfile now exits 0. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01JJnDvpYYk2rTvjkudQUoCk |
||
|
|
d55b1bfeac |
fix(memory): stop reporting a gated native bridge as the active backend (#3228) + fast-uri CVE (#3245)
* fix(memory): stop reporting a gated native bridge as the active backend (#3228) On Windows the #3024 kill-switch makes getRegistry() return null, so every memory read/write silently falls back to the sql.js store (memory.db) instead of the AgentDB corpus (agentdb-memory.db) the bridge would have opened. The reporter measured the consequence: a canary store/retrieve round-trip SUCCEEDS because both halves use the same unintended file, while an existing live-store key returns found:false against 31,673 real rows. The status surface hid the substitution. getHNSWStatus() gated its bridge branch on whether the bridge MODULE was loaded -- which it is, even when the registry is gated off -- so describeBackend() printed "sqlite (bridge, brute-force cosine)" for a store the bridge never touched. Gate on whether the bridge is permitted to be the active path rather than on whether the module resolved. shouldDisableNativeBridge() is sync and a pure function of platform + env, so it is a faithful discriminator and needs no warm registry. describeBackend() now names the gate and its reason, so an upgrade that changes which file receives writes says so. This does not fix the opt-in allocation abort (#2948) or reroute the fallback to the AgentDB corpus; both need Windows validation. It makes the silent case loud, which is what the report asks for first. Also bumps fast-uri 3.1.5 -> ^3.1.6 (resolves 3.1.7), clearing GHSA-5jgf-p345-68v8 (high, host confusion via skipped IDN canonicalization) and the ajv high that inherited it. Same change as #3222 by @aeonframework, applied here because CI was never authorized to run on that PR. Refs #3228, #3222, #2948, #3024 Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01JJnDvpYYk2rTvjkudQUoCk * chore(release): 3.39.0 -> 3.39.1 Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01JJnDvpYYk2rTvjkudQUoCk |
||
|
|
e341ec8c4a |
chore(release): 3.38.23 -> 3.39.0
Ships the ADR-322C receipt number-domain fix (#3229 / #3235). MINOR rather than patch: receipt output changes shape (fractional candidatePolicy values become scale-12 decimal strings) and policySchemaVersion moves v1 -> v2, so pre-fix receipts refuse promotion with 'policy schema changed'. Not MAJOR because no CLI surface or MCP tool signature changed. Existing signed receipts stay valid as history and are deliberately NOT migrated — re-encoding changes the content, hence the ID, hence invalidates the signature. Re-establish a champion through the explicit reset path, which already requires confirmation and a recorded reason. Validated end to end against the built dist before publishing: a receipt carrying the exact candidatePolicy from #3229 encodes to {"alpha":"0.3","subjectWeight":1,"mmrLambda":"0.5","bodyWeight":"1.5", "typePenaltyFactor":"0.5"}, contains zero fractional JSON numbers anywhere in the payload, and verifies VALID. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01J2s8oQsAZjJtJ6inoYRFPj |
||
|
|
384b923986 |
chore(release): 3.38.21 -> 3.38.23
Patch release covering the six commits landed since 3.38.21: - #3221 gate EnhancedModelRouter's forwarded modelId on tier match - #3169 wire embedding-cosine into SmartRetrieval's MMR step - #3184 wire real cold-start measurement, drop the fabricated V2-vs-V3 benchmark - #3177 bound two ReDoS patterns, stateless PII regexes, O(P) confidence pass - #3204 fix two stale main-tree Test Suite failures - #3203 add v3/@claude-flow/mcp to the root npm workspaces 3.38.22 is intentionally skipped: @claude-flow/cli's publish for that version stuck in npm's "staged" state (published umbrellas, cli 404) and the registry refused to republish over it even after unpublish, so all three packages moved to .23 together to restore version lockstep. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01Ff2xRKvYrqXJhefvcapfE1 |
||
|
|
efadf92b97 |
fix(ci): add v3/@claude-flow/mcp to the root npm workspaces so npm ci resolves the unpublished alpha.10 pin (#3203)
Root package.json and v3/@claude-flow/cli/package.json pin
@claude-flow/mcp@3.0.0-alpha.10 (since
|
||
|
|
db4991967c |
chore(release): 3.38.20 -> 3.38.21
Publishes the #3155 fix (fix(memory): stop seeding the bridge's ControllerRegistry with the sql.js dbPath, PR #3156) and the CI-fixing PR #3059 (agentic-flow-agent duration-assertion flake) to npm. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_011N1hncQ1p4pVt15q2VqaQD |
||
|
|
e21aa352fd |
chore(release): 3.38.19 -> 3.38.20
Publishes PR #3092 (fix(statusline): stop pinning intelligence to a hardcoded 0%). Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01BGiC4SoXiGcUHxs4TsFCeh |
||
|
|
127a6546c4 |
chore(release): 3.38.17 -> 3.38.18, @claude-flow/memory 3.0.0-alpha.22 -> alpha.23
3.38.17 was published by a concurrent session mid-race with a stale
package.json (the @claude-flow/mcp pin had been reverted to the broken
3.0.0-alpha.10 by a background helper-refresh process just before publish;
see #3005). npm forbids republishing over an existing version, so cutting
3.38.18 with the verified-correct pin instead of trying to fix 3.38.17.
Also discovered @claude-flow/memory is NOT in @claude-flow/cli's
bundleDependencies (unlike @claude-flow/mcp/codex/security/plugin-agent-federation)
-- it's resolved from the registry via a normal ^3.0.0-alpha.22 semver range,
and that exact version is what's currently published, without the #2977 fix
from
|
||
|
|
16b0dc4d5b |
chore(release): 3.38.16 → 3.38.17
Fixes #2990's root cause at the publish layer: v3/@claude-flow/cli and the claude-flow umbrella both pinned @claude-flow/mcp to 3.0.0-alpha.10, a version that was never published (npm registry tops out at alpha.9). Since @claude-flow/mcp is bundled (bundleDependencies) via a pnpm workspace link, this didn't affect the monorepo build, but it broke plain `npm install` against the published packages and left package.json/pnpm-lock.yaml out of sync with what's actually resolvable. Repinned to ^3.0.0-alpha.9 (the real latest, which already carries the protocolVersion-string fix) and regenerated v3/pnpm-lock.yaml accordingly. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_018ZkgSrVRWNMcXmaFiMZ7Z8 |
||
|
|
13cbd697db | fix(release): enforce CI and idle assignment safety | ||
|
|
21f7c0adb8 | fix(release): align bundled runtime metadata | ||
|
|
392e71912e | fix(mcp): rate-limit authenticated HTTP routes | ||
|
|
2ec82b0cd1 | chore(release): prepare stable 3.38.10 train | ||
|
|
cc5d9c5fe7 | chore(release): bump to 3.38.9 — path-validator symlinked-prefix fix | ||
|
|
0d9a4f7e85 | chore(release): bump to 3.38.7 — HNSW status honesty fix, cache-fingerprint follow-up | ||
|
|
c76bbdcb16 | chore(release): bump to 3.38.6 — codex stdin fix, intelligence cache staleness fix, daemon config restore fix | ||
|
|
506264a9d7 |
chore(release): bump to 3.38.5 — .brain skip, --repo passthrough, secret regex
Ships #2994 (#2911 — ruvnet-brain clones no longer poison ADR indexing), #2995 (#2963 — github_issue_track passes --repo to gh), #2996 (#2931 — hardcoded-secret regex catches shorter/embedded Stripe/OpenAI-shaped keys). Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
7c738174c1 |
chore(release): bump to 3.38.4 — init flag fix + graph edge race fix
Ships #2989 (init --all-agents/--skip-claude/--only-claude/--cloud-mcp were dead kebab-case flag reads) and #2991 (CLI hooks post-task dropped the ADR-130 reinforced-by graph edge due to an unawaited fire-and-forget write racing process.exit(0)). Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
f14453c3b7 |
chore(release): bump to 3.38.3 — hooks intelligence --train fix
Ships #2988: `hooks intelligence --train` now actually distills (#2940) instead of printing a canned success message with no state change behind it. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
8082fbc0f8 |
chore(release): bump to 3.38.2 — removed-agent restore + mcp http foreground fix
Publishes #2986 (fix(migrate): correct removed-agent install suggestion and add `migrate fix --agents` restore, #2985) and #2987 (fix(mcp): mcp start -t http exits after false-success table + doc drift, #2984). Pure bug fixes, no breaking changes -> PATCH per repo semver policy. @claude-flow/cli, claude-flow, ruflo published in lockstep at 3.38.2, all three dist-tags (latest/alpha/v3alpha) verified against the live registry, published tarball pulled and confirmed to contain both fixes. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
711ca3f6fe |
chore(release): bump to 3.38.1 — memory search truncation + persistence honesty fixes
Publishes the #2983 fixes (#2982/#2976 unordered LIMIT truncation in memory search, #2968 sql.js persistence honesty). Pure bug fixes, no API/behavior additions -> PATCH per repo semver policy. Also corrects package-lock.json's top-level version field, which had drifted to a stale 3.35.0 independent of this bump. @claude-flow/cli, claude-flow, ruflo published in lockstep at 3.38.1, all three dist-tags (latest/alpha/v3alpha) verified against the live registry. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
4af1cfdded |
chore(release): bump to 3.35.0 — MetaHarness dependency-contract fix + ADR-381 sequential-evidence governance (#2957)
Minor bump: this release folds in PR #2956 (MetaHarness hardening — repair the dependency contract, strict sequential promotion evidence, ADR-381) plus a follow-up commit on that PR fixing 3 concurrency/epoch-boundary bugs found during review that could silently violate the <=5% family-wise false-promotion guarantee. All backward-compatible additions (new optionalDependencies, new doctor checks, new CLI/MCP surface) — no breaking changes, hence minor not major. Also fixes a stale test assertion in distill-oracle.test.ts: the darwin bench-run command now embeds the pinned @metaharness/darwin version (MH_DARWIN_PIN) per the #2561 cold-npx regression guard, so the test's bare 'darwin bench run' substring check no longer matched the intentional pinned output ('darwin@0.8.3 bench run'). |
||
|
|
491c75a6fa | chore(release): 3.33.0 — ADR-377 AgentDB Retrieval Security Layer (#2876) | ||
|
|
ad8d071d16 |
fix: stop daemon autostart in non-Ruflo projects (#2853)
* fix(daemon): require durable project marker for autostart * chore(release): prepare v3.32.38 |
||
|
|
401e02d511 |
fix: complete reports and consistent initialization for v3.32.37 (#2851)
* fix(metaharness): preserve readiness verdict payloads * test(metaharness): cover blocked genome verdicts * fix(adr): parse bullet metadata and relationships (#2659) * fix(adr): align adr-create with AgentDB schema (#2651) * fix(adr): make index updates idempotent (#2660) * fix(memory): bound session-end graph consolidation (#2628) * fix(memory): align active row visibility (#2652) * fix(memory): honor database path during init * fix(hooks): keep all shim fallback tags aligned * fix(codex): omit unbacked full-template skills * fix(init): generate complete native dual projects * test(memory): isolate path and legacy-row regressions * chore(release): prepare v3.32.37 |
||
|
|
67ff9898c0 |
fix: resolve current runtime and verification defects for v3.32.36 (#2850)
* fix(cli): make runtime status and learning signals truthful * fix(metaharness): accept padded scan severities * fix(codex): make core hooks and status skill native * fix(security): make witness verification hermetic * fix(metrics): expose grounded learning outcomes * fix(hooks): deduplicate project and plugin events * fix(verification): preserve security audit payloads * fix(runtime): stabilize dual memory skills and MCP schemas * fix(cli): harden helper signing and reflexion health * test(release): align helper and container invariants * chore(release): prepare v3.32.36 * test(funnel): align gates with cold-start seed pool * fix(ci): document MCP environment precedence |
||
|
|
3d9bca6d44 | chore(release): prepare v3.32.35 (#2849) | ||
|
|
c3cf2d0ea9 | chore(release): harden memory migration for v3.32.34 (#2846) | ||
|
|
c1957608d4 | fix(autopilot): enforce normalized CLI task sources (#2845) | ||
|
|
388849b3e8 | chore(release): prepare v3.32.32 (#2842) | ||
|
|
77b8dabb97 | chore(release): prepare v3.32.31 (#2841) | ||
|
|
ddd27576cb |
fix(release): ship Capability Brain as a self-contained 3.32.30 train (#2829)
* fix(release): bundle policy and Codex runtimes * fix(release): verify self-contained three-package archives |
||
|
|
1d305b133e |
chore(release): correct stable train to v3.32.29 (#2826)
Preserve the immutable v3.32.28 source release while moving the npm train to collision-free v3.32.29 and federation alpha.18 coordinates. |
||
|
|
dbb1f1e1dd |
feat: capability brain and governed federation plane (#2825)
Adds the live Ruflo capability brain, governed federation and Cognitum product planes, source-bound concurrent harness contracts, ADRs 325-329, and the v3.32.28 guarded release train. |
||
|
|
26c35b59b4 |
chore(release): bump @claude-flow/cli, claude-flow, ruflo to 3.32.9
Patch release covering the statusline/memory-integrity fix batch merged in #2746, #2747, #2748, #2749 (issues #2733, #2735, #2736, #2737, #2742). Also fixes an npm EOVERRIDE conflict this batch introduced: v3/@claude-flow/cli/package.json had gained both a direct optionalDependency on better-sqlite3 (^12.9.0, from #2748) and a self-referential override pinned to an exact "12.9.0" (from #2736) for the same package — npm publish rejects an override that doesn't match its own direct dependency's spec string. Aligned the override to the same "^12.9.0" range so the dedup guarantee holds without the conflict. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
745dfbe327 |
fix(security): dedup better-sqlite3 to patched 12.9.0 across dependency tree (#2736) (#2746)
* fix(security): dedup better-sqlite3 to patched 12.9.0 across dependency tree Fixes #2736 (defense-in-depth mitigation). SQLite's documented WAL-Reset Bug (sqlite.org/wal.html §11) is a race between overlapping checkpoint operations and a WAL-resetting commit that can make a later checkpoint skip a committed transaction, silently losing acknowledged writes and/or corrupting index/table structure. Affects SQLite 3.7.0-3.51.2; fixed in 3.51.3, backported to 3.44.6 and 3.50.7. agentdb's own published dependency floor (`better-sqlite3@^11.8.1`, confirmed in this tree resolving to 11.10.0, which bundles vulnerable SQLite 3.49.2) created a mixed-engine tree alongside this repo's own direct dependency on better-sqlite3 12.9.0 (patched SQLite 3.53.0, via v3/@claude-flow/memory). Multiple concurrent connections (daemon, MCP servers, CLI invocations) issuing wal_checkpoint(PASSIVE) after every memory-bridge store is exactly the race precondition this bug requires. This forces a single deduplicated better-sqlite3 build tree-wide via pnpm overrides, pinned to the exact version this repo's own @claude-flow/memory package already depends on directly (12.9.0, bundling patched SQLite 3.53.0) — no new version to vet, just true deduplication of agentdb's nested resolution into the already-patched copy. Changes (following this repo's existing #2112-lesson override convention — multiple package.json files, each consumed a different way): - v3/package.json: pnpm.overrides (the v3 pnpm workspace root — this is where agentdb's better-sqlite3@11.10.0 actually lived pre-fix) - v3/@claude-flow/cli/package.json: npm-style overrides (effective when @claude-flow/cli is npm-installed standalone via npx) - package.json (root "claude-flow" umbrella): bumped the existing ">=12.8.0" override to an exact "12.9.0" pin, AND added a pnpm.overrides block — the bare "overrides" key alone is silently ignored by pnpm (only read by npm), so the pre-existing override was a no-op for local `pnpm install` at repo root despite being present in package.json for a while - ruflo/package.json: bumped ">=12.8.0" to exact "12.9.0" (npm-style, effective for `npx ruflo@latest`) - v3/pnpm-lock.yaml, pnpm-lock.yaml: regenerated via `pnpm install` Verification: - `pnpm why -r better-sqlite3` (v3/) and `pnpm why better-sqlite3` (root): exactly one resolved version, 12.9.0, everywhere - Confirmed via realpath resolution (not hoisted symlink) from each of the 4 installed agentdb versions' own on-disk directories (1.6.1, 2.0.0-alpha.3.4, 2.0.0-alpha.3.7, 3.0.0-alpha.17) that each now binds the same deduplicated better-sqlite3@12.9.0 copy - `db.prepare('select sqlite_version()').get()` from that binding returns 3.53.0 (>= 3.51.3 patched floor) - v3/@claude-flow/memory test suite: 438/442 passing; the 4 failures are pre-existing Windows path-separator and perf-threshold issues unrelated to SQLite (none of the failing test files touch better-sqlite3/sqlite at all) Not fixed here (upstream, out of reach from this repo): - agentdb's own published package.json floor (`^11.8.1`) is unchanged — this override is a same-repo mitigation, not a fix to agentdb itself. agentdb needs the same bump upstream. Not touched here (explicitly out of scope, separate/riskier change): - The wal_checkpoint(PASSIVE)-after-every-store pattern in memory-bridge.ts (#2558) is left as-is; the issue calls that "defense-in-depth" / optional, and dedup alone removes the mixed-engine race precondition regardless. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(deps): regenerate package-lock.json for better-sqlite3 dedup override package.json pins the better-sqlite3 override to 12.9.0 (patched, fixes the WAL-reset bug) but package-lock.json still resolved a stray top-level better-sqlite3@12.10.0 and was missing the nested better-sqlite3@12.9.0 entries under @claude-flow/memory, agentdb, and agentic-flow — causing npm ci to fail in CI with "Missing: better-sqlite3@12.9.0 from lock file". Co-Authored-By: RuFlo <ruv@ruv.net> * fix(deps): restore better-sqlite3 as direct root optionalDependency The #2736 dedup fix pinned better-sqlite3 to 12.9.0 via a pure "overrides" entry (no direct dependency), which removed the top-level hoisted node_modules/better-sqlite3 that used to exist under the looser ">=12.8.0" override. That silently broke the "graph schema smoke (ADR-130 P1)" CI job: its "npm rebuild better-sqlite3" step (and graph-edge-writer.ts's bare `await import('better-sqlite3')`, which Node resolves by walking up node_modules from the importing file) had nothing at the root to rebuild/resolve, so _openDb() failed closed and insertGraphEdge() silently returned false — 8/22 assertions failing. Restoring the direct optionalDependency (matching what this file already had historically, before the override-only refactor) gives npm a concrete anchor to hoist a single deduplicated copy back to root node_modules, preserving the override's version pin while keeping the graph-edge-writer's resolution path intact. Regenerated package-lock.json accordingly. Verified locally: `npm rebuild better-sqlite3` now finds and rebuilds the root copy, and a direct insertGraphEdge() call against a real better-sqlite3 handle returns true. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(deps): resync v3/pnpm-lock.yaml specifier after merging main Merging main (which carries #2748's direct better-sqlite3 dependency on @claude-flow/cli) forward into this branch left the recorded lockfile specifier at the pre-override "^12.9.0" while this branch's own overrides.better-sqlite3 pin ("12.9.0", exact) is now the effective spec pnpm resolves against — a one-line drift causing `pnpm install --frozen-lockfile` to fail across the whole v3-ci.yml matrix. Regenerated to match. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(memory): force WAL checkpoint before close in graph-edge-writer The "graph schema smoke (ADR-130 P1)" CI job started failing deterministically on Linux runners after the better-sqlite3 dedup (this branch) pinned a single 12.9.0 build tree-wide: TEST 2/3 insert-then-reread assertions found embedding_ref/source_id undefined immediately after _resetBridgeDb() closed the write connection. _resetBridgeDb()'s close() relied on SQLite's implicit "last connection close" PASSIVE auto-checkpoint to flush the WAL into the main file before a same-process sql.js reader re-reads the raw file. That's best-effort, not guaranteed synchronous, and evidently more prone to leaving data in the WAL under Linux CI's I/O/lock timing than on Windows (did not reproduce locally). Not a correctness regression in 12.9.0 itself — a latent timing assumption the dedup made newly observable by changing which exact build backs every connection. Force a blocking `wal_checkpoint(TRUNCATE)` before close so the main file always reflects committed writes before any other reader (same process or otherwise) touches it, regardless of platform timing. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
fb2f92bb2c |
chore(release): bump @claude-flow/cli, claude-flow, ruflo to 3.32.8
Brings all three packages back into version lockstep (claude-flow had been stuck at 3.32.2 while @claude-flow/cli and ruflo advanced to 3.32.7), fixing the "Plugin package install-safety" CI violation. Bundles the pnpm-lock.yaml drift fix (#2719/#2717) and the memory_search namespace-default fix (#2646), both already merged to main, into this release. |
||
|
|
e332689b8c | fix(release): harden hooks, statusline, security, and plugin MCP integration | ||
|
|
72875da937 | chore(release): prepare stable Ruflo 3.32.1 | ||
|
|
3e9122a310 |
feat(routing): default to latest Claude 5/4.x models in tier map + init template
- MODEL_MAP: `sonnet` alias bumped from claude-sonnet-4-6 → claude-sonnet-5 (matches the current Claude 5 family default). Prior pin remains reachable via new `sonnet-4.6` alias for back-compat. - DEFAULT_ANTHROPIC_MODEL and `inherit` now resolve to claude-sonnet-5. - ruflo init template (settings-generator.ts): top-level `model` set to claude-sonnet-5 (previously commented out with a stale sonnet-4-5 hint); `claudeFlow.modelPreferences.default` bumped from opus-4-8 → claude-sonnet-5. - Project `.claude/settings.json` synced with the new template output (model + modelPreferences); removed the stale skillListingBudgetFraction rationale comment (kept the 0.06 value — #1834 still has 358 SKILL.md duplicates, workaround is still load-bearing). - Test updates for #2232 / #1906 regression guards to assert the new sonnet-5 resolution and the new `sonnet-4.6` back-compat alias. Bumps @claude-flow/cli, claude-flow, and ruflo to 3.30.4 (PATCH — no API change, default-model refresh only). All 30 model-resolution/sampling-params tests + 400 commands-deep tests green. Follow-up: sampling-params regex in agent-execute-core.ts (#2357) may need `sonnet-5` added if Sonnet 5 rejects temperature/top_p/top_k like the rest of the Claude 5 family — not touched here because I don't have that behavior confirmed. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
901a10d20e |
chore(release): bump claude-flow + ruflo to 3.28.0
Umbrella and wrapper version bump to match @claude-flow/cli@3.28.0 (#2661 root-fix: repository supervisor, structured telemetry, budget CLI, migration warning). Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
dcfd621d1e |
chore(release): bump claude-flow + ruflo to 3.27.4
Umbrella and wrapper version bump to match @claude-flow/cli@3.27.4 (persistent AgentDB memory on by default). Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
b254e3215e |
fix(statusline): bake in the real CLI version, fixing the npx-only fallback
getPkgVersion()'s runtime candidate scan can't find any version when rendering via a pure npx invocation with no persistent local install: npx installs into an ephemeral, unpredictably-hashed ~/.npm/_npx/<hash>/ directory that none of the probed candidate paths (marketplace, project node_modules, global prefix) can locate. It silently fell back to a hardcoded "3.6" placeholder — confirmed live via an isolated fresh-machine simulation (fresh HOME + fresh npm cache, no prior npx history). generateStatuslineScript() now bakes in the CLI's own real version at generation time (via getInstalledCliVersion(), the same reliable createRequire/findPackageRoot resolution helper-refresh.ts already uses) as getPkgVersion()'s default, replacing the hardcoded placeholder. The runtime candidate scan still wins when it finds something newer (e.g. a later `npm update` in the same project) — this only fixes the fallback. chore(release): bump to 3.27.3 across cli/umbrella/wrapper. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
dbcfe15f3c |
fix(hooks,statusline): validate a real compiled dist before trusting a local CLI candidate
Claude Code's own plugin marketplace mechanism installs by git clone/pull
with no build step, so ~/.claude/plugins/marketplaces/ruflo is a
source-only checkout by construction: bin/cli.js exists on disk but
importing dist/src/index.js from it throws ERR_MODULE_NOT_FOUND on every
real command (confirmed live on a real install — only --version survives
it, since it reads package.json directly).
Both resolveCliBinForHook() (hook-handler.cjs) and resolveCliBinCandidates()
(statusline-generator.ts) picked that doomed candidate first and had no
recovery:
- hook-handler.cjs's spawnDetachedFunnelRefresh()/spawnDetachedAdvisorRefresh()
just gave up silently (`if (!cliBin) return;`) — the funnel promo cache
and ADR-316 advisor tip could never populate for a marketplace install,
on any OS.
- statusline.cjs's getStatuslineData() DID already fall through to the
other candidates and finally npx, but wasted every render's time budget
failing against the broken candidate first — starving the 20s
promo-rotation clock and making the row look frozen/non-rotating even
once it did show something.
Fix: both resolvers now also check for dist/src/index.js next to bin/cli.js
before trusting a candidate. hook-handler.cjs additionally gains a shared
spawnDetachedHookRefresh() that falls back to `npx --prefer-offline
@claude-flow/cli` (detached/unref'd, so the slower cold-start costs nothing
perceptible) when no local candidate has a real dist — mirroring the
robustness the statusline path already had.
Existing installs pick this up automatically via autoRefreshHelpersIfStale
on the next `ruflo`/`@claude-flow/cli` command, no reinstall required.
Co-Authored-By: RuFlo <ruv@ruv.net>
|
||
|
|
7006785577 |
chore(release): bump claude-flow + ruflo to 3.27.0
Umbrella and wrapper version bump to match @claude-flow/cli@3.27.0 (#2661/#2662 daemon flywheel fix). ruflo's ^3.23.0 dependency range already covers the new version; no range change needed. Co-Authored-By: RuFlo <ruv@ruv.net> |
||
|
|
eabf953042 | chore(release): bump to 3.26.1 across cli/umbrella/wrapper (Windows statusline hotfix) | ||
|
|
d0ac73d798 |
feat: Cognitum customer lifecycle funnel — ADR-301..310 + implementation (#2622)
* docs(adr): add ADR-301..305 — Cognitum customer lifecycle funnel New 300-series ADRs defining the ruflo → cognitum.one conversion funnel: - ADR-301: promotional status surface (rotating bottom status row; reaches existing installs via the ADR-174/177 signed helper auto-refresh channel) - ADR-302: one-time post-init capability enrollment prompt - ADR-303: contextual credit-exhaustion recovery/upgrade experience - ADR-304: optional local Meta LLM proxy (localhost:11435 → api.cognitum.one, OpenAI-compatible, local-first) - ADR-305: funnel overview, design principles, success + guardrail metrics Also indexes the new series in the ADR README. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013FqZGy1zZ49JivKUSyqDKH * docs(adr): harden ADR-301..305 per review — trust and funnel-integrity gates - ADR-301: signed content boundaries — messages are schema-validated data only, length-bounded, URL-allowlisted, expiry-cached, and sanitized so copy can never emit terminal control sequences - ADR-302: split enrollment into four independent consent domains (account, proxy-install, telemetry, cloud-routing) with versioned consent receipts; acceptance authorizes auth login only - ADR-303: deterministic error taxonomy with explicit provider codes and a fail-closed classifier; no text-matching of provider messages - ADR-304: mandatory data-plane disclosure before cloud routing; proxy installs local-only, cloud routing off until explicit opt-in - ADR-305: attribution rules (event vocabulary, anonymous rotating funnel ID, 7/30-day attribution windows, 90-day retention, verifiable deletion), ordered gate hierarchy with hard integrity/ health/trust gates, automatic circuit breaker via the signed config channel, and an end-to-end acceptance test for existing installs Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013FqZGy1zZ49JivKUSyqDKH * docs(adr): amend ADR-301/303/304/305, add ADR-306..310 — deployable funnel system Amendments: - ADR-301: existing-install disclosure gate (never promo before disclosure, once per user, decline disables all surfaces), 4:1 educational:promotional content ratio, 30-min repeat cap, no dark patterns, marquee off for screen readers/reduced motion, control precedence chain - ADR-303: Cognitum account service as sole credit authority (GET /v1/credits), canonical CreditErrorCode enum; only COGNITUM_CREDIT_EXHAUSTED triggers the funnel surface - ADR-304: retitled as the proxy *product* ADR; explicit relationship to the internal metallm dev-bridge (shared routing core, versioned compat layer, no implicit contract dependency); runtime deferred to ADR-307 - ADR-305: kill-switch claim corrected — release-bound vs opt-in freshness mechanisms with honest latencies, 24h revocation TTL, last-valid-signed-policy failure mode; normative control precedence (env > enterprise > user > default > remote); two measurement planes (CI release qualification enforces gates; production analytics measures adoption only) New ADRs: - ADR-306: Cognitum auth — PKCE + device flow, keychain-only refresh tokens, incremental scopes mapped 1:1 to consent domains - ADR-307: proxy runtime — Rust single binary, loopback bind + per-user token, platform user services, explicit lifecycle commands, signed no-self-update packaging - ADR-308: versioned public API contract — OpenAPI in both repos, idempotent event ingestion, normative client failure policy - ADR-309: governance — npm-policy commitments, GDPR/CCPA basis, constrained closed event schema with timestamp bucketing, content approval ownership - ADR-310: staged rollout phases 0-6, promotion criteria, three- package rollback discipline, CI gate matrix, final acceptance test Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013FqZGy1zZ49JivKUSyqDKH * feat(funnel): implement ADR-301/302/303/305 funnel system with release gates Core module (v3/@claude-flow/cli/src/funnel/, local-only, zero network I/O): - precedence.ts: ADR-305 control chain (env > enterprise policy > user config > project config > package default > remote policy); a lower source can never re-enable a higher disable - disclosure.ts: ADR-301 existing-install disclosure gate (never_seen / disclosed_enabled / disclosed_disabled), 72h grace window before any message, decline disables all surfaces - messages.ts: signed-content boundaries: schema validation, 80-col grapheme-aware bound, exact-host URL allowlist, expiry, and hard drop of any C0/C1/ANSI/OSC/bidi sequence (drop, never repair) - rotation.ts: deterministic scheduler; promo only in 1-of-5 slots, 30-min repeat cap, educational fills all other slots - consent.ts: ADR-302 versioned receipts for 5 separate domains; grant AND decline recorded; stale policyVersion means re-ask, never carry forward - credit-errors.ts: ADR-303 CreditErrorCode enum + fail-closed classifier over machine-readable provider codes (never message text); only COGNITUM_CREDIT_EXHAUSTED fires the recovery surface, once per session - events.ts: ADR-309 closed event schema, daily timestamp buckets, bounded local queue, telemetry-consent-gated, opt-out deletes ID+queue - enrollment.ts + promo.ts: surface orchestrators Surface integrations: - hooks statusline --json now computes a promo field (all gates run server-side; failures never break the statusline) - generated statusline.cjs renders the bottom promo row with defense-in-depth re-sanitization + env/CI gates at render time; repo-root artifact regenerated (drift guard green) - init: one-time post-init capability enrollment (--no-signup flag, CI/non-TTY auto-skip, records only the account consent domain) - new command: ruflo funnel status|disable|enable|id - doctor gains a funnel component reporting effective state + deciding precedence source (enterprise audit verification) Contracts and gates: - v3/docs/api/cognitum-v1.openapi.yaml: ADR-308 v1 contract (8 endpoints, error taxonomy mirrored 1:1, normative failure policy, signed policy feed schema with 24h TTL cap) - .github/workflows/funnel-gates.yml: ADR-310 hard gates: invariant suite + runtime suppression proofs (promo in CI = 0, RUFLO_FUNNEL=0 suppression, opt-out persistence, non-interactive init) - __tests__/funnel.test.ts: 50 tests mapping 1:1 to the ADR-310 gate list Verified: cli-core/swarm/memory/neural/security/cli builds green; funnel suite 50/50; statusline-cost-display drift guard + runtime 8/8; init-wizard-bugs and p1-commands green; live smoke of the funnel lifecycle, statusline promo gates (fresh shows disclosure, CI shows nothing, RUFLO_FUNNEL=0 shows nothing, post-grace rotates educational), doctor component, and init under CI. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013FqZGy1zZ49JivKUSyqDKH * fix(funnel-gates): mirror the green Build V3 setup (pnpm 8, frozen lockfile, workspace build) The runtime-suppression job failed on the PR because pnpm 9 with a filtered install resolved the bare-semver workspace deps (@claude-flow/cli-core etc.) from the npm registry instead of linking the workspace packages, so the cli tsc build could not find cli-core's dist. Copy the exact setup the passing Build V3 job in v3-ci.yml uses: pnpm/action-setup@v6 pinned to pnpm 8, pnpm install --frozen-lockfile over the full workspace, and a workspace-wide pnpm build. Also install pyyaml explicitly before the OpenAPI parse check. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013FqZGy1zZ49JivKUSyqDKH * chore(helpers): pending-insights runaway-storage guard in intelligence.cjs Captured from the session's self-learning hook runtime: recordEdit now caps the append-only pending-insights file at ~512KB by keeping the most recent 2000 lines when consolidation has not drained it, so it can never grow unbounded. Non-fatal, statSync-per-edit cost only. Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_013FqZGy1zZ49JivKUSyqDKH * feat(funnel): rotating sponsor disclosure, statusline redesign, auto-update ## Statusline (client render) Reorganized 4 rows by purpose (Architecture / Runtime / Health / AgentDB): - suppress zero/healthy fields; glyph-only for 🧠 memory % and 💾 RAM MB - drop DDD % duplicate, drop ADR denominator, drop opaque "◆ DB" marker - "Target 150x-12500x" → "Goal 150x-12500x" (plain language) - Health row hides on NONE; collapses to "✓ Security ✓ No CVEs" when clean, reads "N vulnerabilities" (not "CVE checks 0/3") on unfixed findings - kind-based row color: brightCyan for disclosure, brightPurple for promotional sponsor, yellow for educational — reads as *what it is* ## Funnel promo row (ADR-301/305/309) - Rotating disclosure: 3 copy variants on a deterministic 5-min slot with a shared Cognitum sponsor URL. Neutral framing — no "Sponsored by"/ "Powered by" (would read as advertising and lose OSS trust). - OSC 8 hyperlink wrapper: allowlist ships in renderer (cognitum.one hosts only), https-only, TMUX/CI/TERM=dumb suppression, kill-switch env var, defense-in-depth label re-sanitization. Broken URL / non-https / non-allowed host → plain label, never a raw escape. - Attribution: attributionUrl() decorates every outbound funnel link with utm_source=ruflo · utm_medium=statusline · utm_campaign=<kind> · utm_content=<msg-id>. Client-side link builder, ZERO runtime network call — API-down has no effect on render. `fid` (pseudonymous funnel ID) appended only under telemetry consent (ADR-309 privacy default). - Defense in depth: attributionUrl rejects non-https schemes at build time in addition to renderer's OSC 8 allowlist. ## Auto-update for existing installs - statusline.cjs added to CRITICAL_HELPERS + executor.ts + sign-helpers.mjs. - helper-refresh.ts fallback generates statusline.cjs when the installed package isn't resolvable. - Regen script scripts/regen-statusline-artifact.mjs keeps root artifact in lockstep with the generator (drift-guard test enforces). PUBLISH-TIME REQUIRED (only ruvnet-owned key can do): re-run scripts/sign-helpers.mjs with the Ed25519 signing key so helpers.manifest.json includes statusline.cjs's SHA-256. Without it, auto-refresh fail-closes (intended: tampered helper refuses install). ## Tests: 50 → 57 (+ statusline-cost-display drift guard passes) - parameterized invariant over every DISCLOSURE_TEXTS variant - sponsor URL shape (https + cognitum.one) - 5-min rotation determinism - attributionUrl: UTM shape, absent fid without consent, non-https rejection, malformed base URL verbatim - API-down design lock: promo.ts contains no fetch/https/XMLHttpRequest Co-Authored-By: RuFlo <ruv@ruv.net> * fix(statusline): promo row flicker — stale-while-revalidate cache The funnel promo row would appear on cache warm-up then vanish on the next render whenever the 60s cache TTL expired mid-session and the CLI call either failed, timed out, or was resolved to a bin that returned no promo. Root cause: getStatuslineData() fell through to buildLocalFallback() on CLI failure, and the fallback returned a stub object with no `promo` field. Fix: stale-while-revalidate on the /tmp cache. - readCache() now returns { fresh, data }. The TTL only decides whether the data is fresh; the payload comes back either way. - getStatuslineData(): fresh cache → return immediately. Else try the CLI. On CLI failure, if we have any prior cache data, re-apply local overlays and return it. Only if we've never had a good CLI response do we fall to buildLocalFallback(). Effect: the promo row survives CLI hiccups, timeouts, and cache-expiry mid-render. Live verified: cache backdated 5 min, all 3 CLI bins disabled — row still renders the last known disclosure. Test: pins the generator template shape so a future edit breaking the readCache freshness split or the stale-fallback path trips CI. 57 → 58. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(statusline): 3-line design + persistent promo memo Two related fixes for observed live-session bugs. ## 3-line design (promo as line 1) Claude Code truncates the statusline past line 4 with the system-guidance / input-prompt line. The previous 6-row layout (header + separator + 4 purpose rows + promo) put the funnel row on line 6, so it was silently dropped by the viewport. New layout, exactly 3 lines: Line 1 — Promo / disclosure (funnel row, ADR-301 surface) Line 2 — Header (version · git · model · timing · ctx · cost) Line 3 — Compressed ops (Swarm · Hooks · 🧠 · 💾 · Health) Everything on the previous 4 individual rows is now on the ops line, dot- separated. Diagnostic detail (Domains, ADRs count, vectors, MCP count, DB marker) moves behind `ruflo status --verbose` per the earlier design discipline you documented ("Show healthy state only when it confirms readiness. Show zero values only when zero is actionable. Show failures immediately."). ## Persistent promo memo Even with stale-while-revalidate cache, promo would blink out when an older `@claude-flow/cli` cached by npx succeeded but returned JSON with NO promo field. Cause: the older version predates ADR-301, so its statusline JSON schema is missing our field. The cache path only fires when the CLI THROWS — a promoless success clean-writes. Fix: `~/.ruflo/statusline-promo.json` — a 6h-TTL memo of the last known good promo. Every successful render writes it. Every code path (fresh-cache / CLI-success / stale-cache / cold-fallback) calls `overlayMemoPromo(data)` which injects the memo IFF `data.promo` is missing. The funnel row now survives: - fresh cold cache + working CLI ← memo not needed - stale cache + CLI timeout ← stale-while-revalidate path - cache wiped + CLI down ← memo overlay (proven live) - working CLI, promoless response ← memo overlay (the new fix) Live proof: cache wiped, all 5 known `cli.js` bins renamed to `.disabled`, render still emits the 3-line output with promo on line 1. ## Tests: 58 → 60 in funnel suite, 66 → 68 total Pinned in the generator template: - 3-line ordering (promo push before header push before ops push) - PROMO_MEMO_FILE + readPromoMemo + overlayMemoPromo helpers exist - overlay is called on every code path (spot-checked by call count) Co-Authored-By: RuFlo <ruv@ruv.net> * fix(statusline): 3-line order — RuFlo header · ops · promo (top-to-bottom) Per user preference: RuFlo header must be line 1 (not the promo/disclosure row). Reordering the render: Line 1 — Header (▊ RuFlo · git · model · timing · ctx · cost) Line 2 — Ops (Swarm · Hooks · 🧠 · 💾 · Health) Line 3 — Promo (funnel disclosure / educational tip / sponsor) Promo stays within the visible 3-line viewport so Claude Code doesn't truncate it with the system-guidance line. Memo + stale-while-revalidate safety net from the previous commit is unchanged — promo remains visible even when the CLI returns a promoless response. Test invariant updated to pin the new order (header push < ops push < promo push in the generator source). 68/68 tests still pass. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(statusline): underline the promo label as a clickable CTA The sponsor / disclosure row currently reads as flat text — users don't know it's clickable. Two visual affordances added: 1. ANSI underline ([4m / [24m) on the label portion so terminals show it as a clickable link even when they don't render OSC 8 hyperlinks (a universal cue: underline = interactive text). Combined with the existing OSC 8 wrap, modern terminals get a real hyperlink; legacy terminals get a visual affordance. 2. The trailing "· disable: ruflo funnel disable" instruction now renders dim + non-underlined + outside the OSC 8 wrap. It reads as metadata ("here's how to turn it off") rather than as part of the link target (which would falsely imply that clicking anywhere on that text goes to Cognitum). Split happens on the exact anchor " · disable" — educational tips with no disable tail keep their whole text rendered plainly (no underline, no OSC 8, since they have no URL). Test locks the split-and-underline pattern in the generator template so a future refactor that reunifies the row trips CI. 60 → 61 funnel tests · 68 → 69 total. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(funnel): ADR-308 event transport + Cloud Function reference impl Phase 2 client-side telemetry + reference server. Wires the funnel event queue (v3/@claude-flow/cli/src/funnel/events.ts already exists) to the Cognitum analytics endpoint via a fail-silent HTTP batcher, plus an out-of-band credit-exhaustion notifier. ## Client transport (v3/@claude-flow/cli/src/funnel/event-transport.ts) ADR-308 contract: - POST /v1/events with Idempotency-Key header (UUIDv4 per batch) - Consent-gated: zero network activity when `telemetry` consent is off - Bounded batches (MAX_BATCH = 100), exponential backoff on failure, capped at 30x base interval (~30 min) - 4s POST timeout — telemetry never stalls the CLI - Rejects non-https endpoints inside the transport (defense in depth on top of the client-side allowlist) - Credit-exhaustion detection: 402 response OR body containing the exact ADR-303 machine-readable code triggers the notifier ## Credit notifier (v3/@claude-flow/cli/src/funnel/credit-notifier.ts) Persistent user-visible flag at ~/.ruflo/credit-status.json: - markCreditExhausted() — idempotent, stable `since` timestamp - clearCreditStatus() — stamps `cleared`, drops the exhausted flag - creditExhaustedNotice() — user-facing single line with humanized age - readCreditStatus() — inspector for status/tools ## Server reference (services/cognitum-analytics/) Cloud Function reference implementation: - index.js — POST /v1/events handler, Firestore writes to funnel_events + funnel_aggregates + funnel_credit + funnel_idem collections - package.json — Node 22 + functions-framework + Firestore SDK - deploy.sh — gcloud CLI deploy (gen2, us-central1, 402-on-cap ceiling) - sample-batch.json — fixture for smoke tests - README.md — layout, local run, deploy, verification DEPLOY IS HUMAN-DRIVEN. The autonomous loop does not run deploy.sh — that requires a live gcloud session with cloudfunctions.admin on cognitum-20260110 and is outside the hard-fence for automated actions. Everything up to the deploy is scripted; the human runs `./deploy.sh` when ready. ## Tests: 68 total funnel tests (61 → 68, +7 new) - Transport defaults (https + batch cap + backoff floor + timeout ceiling) - No-consent no-op (zero network activity) - Non-https endpoint rejected inside transport - markCreditExhausted idempotence (stable `since`) - clearCreditStatus stamps `cleared` - creditExhaustedNotice humanized age copy - Null return when not exhausted (no false surface) Co-Authored-By: RuFlo <ruv@ruv.net> * feat(funnel): funnel.ruv.io domain mapping for analytics endpoint The cognitum-analytics Cloud Function is now deployed on cognitum-20260110 and reachable at funnel.ruv.io/v1/events (Cloud Run domain mapping) as well as the raw Cloud Run URL. The client's DEFAULT_ENDPOINT points at the ruv.io subdomain so it: 1. survives Cloud Run hostname-hash changes on redeploy, 2. keeps analytics attribution on rUv's own domain (not cognitum.one, which is a separate product surface), 3. reads honestly to users: telemetry for the OSS CLI lives with the OSS author, not with the cognitum.one commercial product. DNS is a Cloudflare CNAME funnel.ruv.io → ghs.googlehosted.com, unproxied so Cloud Run terminates TLS directly. README documents the recreate-from-scratch flow using the CLOUDFLARE_API_TOKEN in Secret Manager on cognitum-20260110. Live infrastructure state: - Cloud Function cognitum-analytics deployed us-central1, revision 00001 - Firestore collections funnel_events / funnel_aggregates / funnel_credit / funnel_idem writing on first accepted batch - Smoke test at deploy time returned {"ok":true,"accepted":1} - Domain mapping created, DNS resolving, cert provisioning pending (Cloud Run polls hourly) Co-Authored-By: RuFlo <ruv@ruv.net> * docs(adr-311): funnel analytics — server-side split to dedicated repo Server implementation of the ADR-308 /v1/events endpoint has been extracted to its own repo: github.com/cognitum-one/ruflo-funnel-api Reasoning captured in ADR-311: - Commercial-side changes (rate limits, tenant model, BigQuery export) don't churn the OSS CLI PR history. - ADR-308 client contract remains the single source of truth for the wire format; the server can be forked or swapped without touching the CLI. - Server security surface (Firestore rules, IAM, key rotation) belongs with whoever runs the endpoint, not tangled with CLI release cadence. Also captures the concrete deployment decisions that came out of standing up the endpoint against cognitum-20260110: - Runtime: Cloud Function gen2, Node 22, us-central1, 256 MiB - Domain: funnel.ruv.io (Cloud Run mapping, Cloudflare CNAME unproxied) - Storage: 4 Firestore collections (funnel_events / _aggregates / _credit / _idem) with ADR-309 retention rules - Credit signal: HTTP 402 + body 'COGNITUM_CREDIT_EXHAUSTED' wires directly into the ADR-303 recovery surface via credit-notifier.ts services/cognitum-analytics/ in this repo is now a pointer README to the dedicated repo; the four source files were verbatim-committed as the initial commit there. Live-verified 8/8 API contract tests + Firestore writes across all 4 collections at time of adoption. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(funnel): remote-served message rotation + agentics.org sponsor + settings command Three linked changes to the funnel rotation surface. ## Remote-served messages (ADR-311 amendment) New client transport `message-transport.ts`: - GET https://funnel.ruv.io/v1/messages (raw: https://cognitum-analytics-63rzcdswba-uc.a.run.app/v1/messages) - 6h TTL local cache at ~/.ruflo/funnel-messages-cache.json - Every fetched message validated through ADR-301 isValidMessage() — schema, host allowlist, control-char strip, 80-col cap — before it can display - Best-effort: fetch failures leave cache intact; no network call blocks render (fire-and-forget from rotation.selectMessage) - Kill switch: RUFLO_FUNNEL_MESSAGES=0 or RUFLO_FUNNEL=0 - Bounded cache: ≤ 128 KiB, ≤ 200 messages - Non-https rejected at builder AND host allowlist (defense in depth) New pool merger `eligibleMessagesFromPools()` in messages.ts: - Remote pool authoritative (admin edits without a CLI release) - In-code pool fallback (cold starts, API-down, kill-switched) - Dedup by `id` — remote wins over in-code for the same id Rotation kicks a background refresh on every selectMessage() call so the first fresh render after CLI startup lands within seconds. ## Server side (cognitum-one/ruflo-funnel-api@521205a) - Added GET /v1/messages handler (single router by req.path in the same function; POST /v1/events unchanged) - Firestore collection funnel_messages with { id, class, text, url?, active } - Cache-Control: public, max-age=21600 for CDN + client caches - Firestore seeded with 23 initial messages (via seed-messages-rest.sh): 16 educational (ruflo tips + tricks) 4 promotional Cognitum 3 promotional agentics.org - Verified live: 200 OK, 23 messages, all 0 rejected by client pipeline ## Copy discipline + settings command - ALLOWED_URL_HOSTS + PROMO_LINK_HOSTS gain agentics.org (both wire layers need it for OSC 8 to render the link) - DISCLOSURE_TEXTS copy: "· disable: ruflo funnel disable" → "· manage: ruflo settings" — user-facing command surface no longer leaks the internal "funnel" term - New `ruflo settings` command (settings.ts) as a friendly wrapper over the existing funnel primitives: ruflo settings Overview + current state ruflo settings notices status Notices row state ruflo settings notices off Turn off (persistent) ruflo settings notices on Re-enable ruflo settings notices id Pseudonymous notices ID - getPromoRow split anchor moved from " · disable" → " · manage" (so only the linked label is OSC 8 wrapped, tail stays dim/plain) ## Tests: 68 → 76 (+8) - Every disclosure variant: no `\bfunnel\b`, contains `manage`, contains `ruflo settings`, ≤ 80 cols, Cognitum-attributed - Split anchor in generator: " · manage" (not " · disable") Co-Authored-By: RuFlo <ruv@ruv.net> * feat(funnel): impressions + click tracking + coarse geo (ADR-311 amend) Adds the analytics coverage that PR #2622's initial funnel work deferred: impressions, clicks, and coarse geo. Consent-gated end-to-end; nothing new about privacy — same closed vocabulary, same daily-bucket timestamps, same pseudonymous UUID discipline. Wired against the live Cloud Function on cognitum-20260110 + Firestore. ## Client — impression firing + click-tracked URLs - FunnelEventName vocabulary gains `promo_impression` + `promo_open` (matches server; ADR-305 amendment recorded in ADR-311 §6) - FunnelEvent schema gains optional `messageId` (≤ 64 chars, [a-z0-9-]) — the join key across impression → click → conversion - recordFunnelEvent() accepts an options object for `messageId` + `now` (backwards-compat with the Date positional form) - rotation.selectMessage() fires `promo_impression` for the selected message on every render — consent-gated, batched via existing transport - attribution.clickTrackedUrl() wraps promotional URLs in the server-side click-redirect so `promo_open` fires before the browser leaves. Disclosure/educational rows still use attributionUrl direct (no click tracking on disclosure) - promo.ts uses clickTrackedUrl for `msg.class === 'promotional'` ## Server (cognitum-one/ruflo-funnel-api@37f584b — deployed live) - KNOWN_EVENTS gains promo_impression + promo_open - validEvent() accepts optional messageId via MESSAGE_ID_RE allowlist - New `GET /v1/click/{messageId}?to=<https-url>` handler: - messageId validated against MESSAGE_ID_RE (prevents path-traversal or forged doc lookups) - `to` must be https AND host must be in CLICK_ALLOWED_HOSTS (cognitum.one + agentics.org variants — compiled in, not Firestore-editable; no open-redirect vector) - Coarse geo from CF-IPCountry / X-Appengine-Country (ISO-3166 alpha-2 country ONLY — never city, never lat/long; ADR-309 privacy invariant) - Firestore write: funnel_events doc + funnel_aggregates row keyed by (surface, event, day, release, messageId, country) - Firestore hiccup NEVER blocks the redirect — user intent > analytics - 302 with Cache-Control: no-store so aggregators see every click - Router extended to match /v1/click/{msgId} paths ## Verified live at commit | Test | Result | |---|---| | Click w/ good target + fake CF-IPCountry:US | 302 → cognitum.one; Firestore captured US | | Click w/ non-allowed target (evil.com) | 400 DISALLOWED_TARGET | | Click w/ http:// target | 400 DISALLOWED_TARGET | | Click w/ `..` path traversal | 405 (routed as method-not-allowed) | | POST promo_impression event | 200 accepted:1 | | POST promo_open event | 200 accepted:1 | | POST event w/ malformed messageId | 200 accepted:0 dropped:1 | Firestore verified: promo_open with `country: US`, `via: click-redirect`, `messageId: promo-cognitum-meta-llm`. Aggregate row present with `count: 1` keyed by messageId+country. ## Coverage summary (ADR-311 §8) - Impressions per message per day: `promo_impression` events + aggregates - Clicks per message per day: `promo_open` events + aggregates - CTR: ratio of the two above - Geo distribution: `country` field on `promo_open` - Conversions: existing `signup_opened` / `account_created` / `proxy_activated` - Notices disabled rate: existing `funnel_disabled` Zero PII, zero prompt content, zero paths — everything remains closed enum, allowlisted message id, ISO country code, or daily bucket. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(statusline): style "ruflo settings" as bold command, not a dead link User feedback: "the area don't link to anything, manage: ruflo settings" — clarified they expected "manage: ruflo settings" to be clickable/actionable. It can't be a real link: a terminal has no safe way to execute a shell command from a click — that would let any server-served promo message run arbitrary commands on the user's machine. So instead of leaving it looking like inert plain text (which reads as broken/half-finished), it now gets its own visual treatment: ✨ <label, underlined + OSC 8 link> · manage: <ruflo settings, BOLD> - "manage: " stays dim (a connector word, no action implied) - "ruflo settings" renders BOLD, deliberately WITHOUT underline or OSC 8 — bold signals "this is the important bit, copy/type it" without the false affordance of "click me" that underline would carry Split changed from `text.indexOf(' · manage')` to the more precise `text.indexOf(' · manage: ')` so the exact command substring can be isolated for its own styling. getPromoRow() now returns three concatenated segments instead of two: label(+OSC8), dim connector, bold command. Test updated to assert: label sandwiched in UL_ON/UL_OFF + OSC8, connector in DIM_ON/DIM_OFF, command in BOLD_ON/BOLD_OFF, and — critically — that the command is NEVER wrapped in underline or safeTerminalLink (regression guard against accidentally making a "command" look clickable again). Verified via hex dump of the live render: ESC[1m immediately before "ruflo settings", ESC[22m immediately after, no ESC[4m or OSC 8 escape anywhere near it. Co-Authored-By: RuFlo <ruv@ruv.net> * fix(funnel): use raw Cloud Run URL until funnel.ruv.io cert lands funnel.ruv.io's TLS cert has not yet provisioned (Cloud Run domain mapping created 2026-07-10 18:33 UTC; Google's cert issuance is async and still pending as of this commit — verified: curl to funnel.ruv.io returns curl exit 35 / HTTP 000, raw Cloud Run URL returns 200). Every client fetch to messages/events/click was silently timing out (by design — fail-silent), so: - the remote 23-message pool never reached any installed CLI - message-transport's cache file never got created - rotation only ever showed the 3 static in-code disclosure variants All three endpoint defaults now point at the raw Cloud Run URL: https://cognitum-analytics-63rzcdswba-uc.a.run.app/v1/{events,messages,click} Marked TEMP in comments. Flip back to funnel.ruv.io once its cert is live (monitor: curl -o /dev/null -w '%{http_code}' https://funnel.ruv.io/v1/messages). ## Live verification performed this commit 1. Forced message-pool refresh — 23/23 messages accepted, 0 rejected 2. Selected messages across 8 consecutive 20s rotation slots — 8 distinct ids returned (7 educational + 1 promotional), confirming rotation moves 3. Impressions queued locally (8/8), consent-gated 4. Flushed queue to live server — 8/8 accepted, queue drained to 0 5. Fired the click-redirect for the selected promotional message with a forged CF-IPCountry: CA header — 302 to agentics.org with UTM+fid intact 6. Firestore confirmed both events landed: promo_impression messageId=promo-agentics-community promo_open messageId=promo-agentics-community country=CA via=click-redirect 7. Total promo_impression docs in funnel_events: 9 (8 new + 1 prior) Co-Authored-By: RuFlo <ruv@ruv.net> * feat(funnel): zero local promo content — fully remote-served, fail-closed Per explicit direction: no local promo content or URLs should ship in the CLI at all. This completes the ADR-311 remote-message architecture: disclosure text, educational tips, and promotional messages are now ALL served exclusively from the Cloud Function / Firestore feed. If the feed is unreachable and no prior fetch has succeeded, the promo row renders nothing — there is no local fallback content to degrade to. ## What changed - messages.ts: MESSAGES array emptied to []. Zero message text/URLs ship in the package. isValidMessage() extended to accept a new 'disclosure' class alongside educational/promotional, with an invariant that disclosure-class text must retain the exact " · manage: ruflo settings" tail (dropped, never repaired, if missing). - types.ts: FunnelMessageClass extended to 'educational' | 'promotional' | 'disclosure'. - disclosure.ts: removed the hardcoded DISCLOSURE_TEXTS/DISCLOSURE_TEXT/ DISCLOSURE_SPONSOR_URL constants and selectDisclosureText(). Replaced with selectDisclosureMessage() — deterministic 5-min-slot selection over the remote pool filtered to class==='disclosure', returning null when that pool is empty (cold start / API down). The disclosure state MACHINE (never_seen / disclosed_enabled / disclosed_disabled tracking) stays 100% local — that's app state, not promo content. - promo.ts: getFunnelPromo() now sources the disclosure row from selectDisclosureMessage(); returns null (fail-closed) when unavailable. Also wires the previously-defined-but-never-fired 'disclosure_shown' event so disclosure impressions are now tracked alongside promo_impression. - statusline-generator.ts: PROMO_LINK_HOSTS gains the click-redirect hosts (funnel.ruv.io + the raw Cloud Run hostname) — these are DIFFERENT from the final-destination hosts (cognitum.one/agentics.org); without this the renderer's independent host-allowlist check correctly refused to OSC-8- wrap click-tracked URLs, which was silently breaking every clickable link this session had just added. ## Server (cognitum-one/ruflo-funnel-api@698aa73 — deployed live) - All 16 educational tips now carry url: https://cognitum.one and a trailing 🔗 glyph (checked to fit the 80-col bound, max observed 78/78). - 3 disclosure-class messages seeded (disclosure-1/2/3), matching the copy this session iterated on, now server-authoritative instead of hardcoded. - promo.ts routes EVERY message with a url (not just class==='promotional') through the server click-redirect, so click tracking is uniform across the whole rotation. - Firestore funnel_messages collection: 26 total (16 educational + 7 promotional + 3 disclosure), all verified live via GET /v1/messages. ## Verified live end-to-end - GET /v1/messages returns 26 messages, 16/16 educational have url set. - Rendered statusline shows a real educational tip (edu-doctor) with a working OSC 8 hyperlink to the click-redirect, underline, 🔗ical suffix. - Click-redirect → 302 to cognitum.one with UTM + fid intact; Firestore captured both promo_impression and promo_open for the same messageId. - Fail-closed proven via test: selectMessage()/selectDisclosureMessage()/ getFunnelPromo() all return null when the remote cache is unseeded. ## Tests: 68 → 70 funnel (78 total incl. drift-guard), all green - New: "ships ZERO local messages" pins MESSAGES === []. - New: disclosure-class validation (manage tail required). - New: 3 fail-closed tests (selectDisclosureMessage / selectMessage / getFunnelPromo all null on unseeded cache). - Rewrote disclosure-variant + promo-orchestrator tests to seed a mock remote cache (matching message-transport.ts's on-disk shape) instead of asserting against removed local constants. Co-Authored-By: RuFlo <ruv@ruv.net> * docs(adr-312): usage-limit downtime prevention — researched, phased plan Direct instruction was to review Claude Code's actual CLI source (not just docs) to determine feasibility of detecting approaching/hit usage limits and surfacing a Cognitum meta-LLM proxy CTA as a downtime- prevention / session-extension mechanism. ## Research performed (grounded against @anthropic-ai/claude-code@2.1.107) Inspected /usr/lib/node_modules/@anthropic-ai/claude-code/cli.js directly. Findings: 1. A real internal rate-limit state object exists (module var, referred to in the ADR by its minified name since it will rename on any version bump): { status: allowed|allowed_warning|rejected, resetsAt (epoch sec), rateLimitType: five_hour|seven_day|seven_day_opus| seven_day_sonnet|overage, utilization (0-1 float), unifiedRateLimitFallbackAvailable, isUsingOverage }. 2. It's sourced from REAL Anthropic API response headers (anthropic-ratelimit-unified-status/-reset/-fallback/-{type}- utilization etc.) — confirmed via string match in the bundle. The exact "You've used N% of your session limit · resets HH:MM" banner text is generated from this exact object by a UI-only formatter. 3. This state is NOT exposed through any current extension point — checked exhaustively, empirically: - statusLine stdin JSON: confirmed absent (only model/context_window/ cost fields exist — verified against ruflo's own parser) - Hook events: 28 hook names exist, none confirmed to fire on rate-limit transitions - Debug logs: EMPIRICALLY checked an existing 11,424-line debug log at default level — zero occurrences of any rate-limit header - No CLI command / MCP resource surfaces it - The only consumer is an internal React hook wired to Claude Code's own TUI, unreachable from outside its process ## Decision: 3-phase plan - Phase 0 (buildable now): manual/self-reported flag — `ruflo settings notices rate-limited` — reusing the exact credit-notifier.ts pattern from ADR-303/311. Honest that this is user-reported, not detected. - Phase 1 (blocked on upstream): file a Claude Code feature request to expose the real signal via statusLine JSON or a new hook event. Explicitly does NOT recommend building against the current minified internal names — fragile, version-coupled, would silently break. - Phase 2 (once Phase 1 lands): wire the real signal into rotation with a priority override analogous to ADR-303's credit-exhaustion surface; new closed-vocabulary events rate_limit_warning_shown / rate_limit_exhausted_shown; same consent-gated click-tracking as every other promo message. No code changes in this commit — ADR only, per the explicit request. Co-Authored-By: RuFlo <ruv@ruv.net> * feat(funnel): sponsored-downtime capacity via cognitum-one/meta-proxy (ADR-312/313) ADR-312 documents grounded research into detecting an approaching/hit Claude usage limit: direct inspection of the installed Claude Code CLI (v2.1.107) found the rate-limit state is populated from response headers (anthropic-ratelimit-unified-status/-reset/-fallback/-*-utilization) that are NOT exposed to hooks, the statusline JSON, or the debug log today (confirmed by grep — zero occurrences in an 11k-line debug log). Automatic detection is blocked on Anthropic exposing this state; documents a 3-phase plan (manual flag now, wait on upstream, auto-wire once available). ADR-313 implements Phase 0: a manually-set rate-limit flag (`ruflo settings notices rate-limited [--clear]`) that, once set, preempts normal promo rotation with a sponsored-capacity CTA — same precedent as ADR-303's credit-exhaustion override. Two states depending on consent: an enable CTA, or a quiet "active" confirmation once `ruflo proxy sponsor-enable --yes` has been run. Client-side (this commit): - funnel/rate-limit-notifier.ts — TTL'd flag read/write/clear, mirrors credit-notifier.ts's shape - funnel/promo.ts — priority-override hook, reachable only after the disclosure invariant is satisfied (ADR-301 compliance preserved) - commands/proxy.ts — sponsor-enable/disable/status/clear subcommands; writes both the consent receipt (source of truth) and a mirror flag into ~/.ruflo/proxy-config.toml, the file the Rust proxy binary reads - funnel/types.ts, consent.ts, events.ts — new 'sponsored-downtime' consent domain and sponsor_mode_enabled/disabled/capacity_exhausted events - 10 new tests (rate-limit notifier + priority override), 80/80 passing Server-side (separate private repo, already built/tested/pushed): cognitum-one/meta-proxy — Rust/axum binary routing local/cloud/sponsored data planes, per-user bearer token, loopback-only bind by default, never falls back to sponsored capacity implicitly. Verified end-to-end: the Rust binary correctly reads the same ~/.ruflo/proxy-config.toml this commit's `sponsor-enable` command writes. * docs(adr-313): addendum — proxy needed /v1/messages, not /v1/chat/completions Verification found the shipped meta-proxy scaffold spoke the wrong wire protocol for Claude Code (OpenAI chat-completions instead of the Anthropic Messages API Claude Code actually POSTs to). Fixed in cognitum-one/meta-proxy and verified live end-to-end with the real installed Claude Code CLI against the live apicompletions Cloud Run service. Documents the fix and the remaining gap (no automated sponsored-key provisioning yet). * docs(adr-313): addendum — fourth Passthrough plane preserves subscription usage Setting the env vars needed to reach the proxy at all previously meant giving up subscription-based auth entirely, all the time, not just when rate-limited. Documents the new default Passthrough plane (real Anthropic via the user's own OAuth token, read-only from Claude Code's own credentials file) and the live verification of all four planes switching correctly within one continuous session. * fix(statusline): trailing blank line so the input prompt gets breathing room The statusline's last row butted directly against Claude Code's input prompt with no visual separation. generateStatusline() now returns lines.join('\n') + '\n', so combined with console.log's own trailing newline the rendered output ends in exactly one blank line. Regenerated both committed .claude/helpers/statusline.cjs copies (root + package) so the drift-guard test stays in lockstep. Two new tests: a source-level pin on the generator (can't silently regress) and a runtime check on the actual rendered bytes (exactly one blank line — not zero, not two). * fix(helpers): re-sign manifest for the statusline trailing-newline fix The earlier statusline fix ( |
||
|
|
5727bf02b8 |
chore(release): 3.25.1 — de-Lattice the WASM embedder tier + enforceable no-stub mode
#2582: renamed the fictional 'Lattice' embedder tier to an honest opt-in generic WASM-embedder seam (no 404 default package; inert unless RUFLO_EMBED_WASM_PKG is set), and added RUFLO_REQUIRE_REAL_EMBEDDINGS strict mode that makes hash last-resorts throw instead of silently returning meaningless vectors. Additive, fail-closed, zero-regression (embeddings still resolve to ruvector ONNX). Co-Authored-By: RuFlo <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01S7GYqnVUVxBfZ5W8znqry3 |