rotate: merge wip/2026-08-07 (109 commits — #724 recovery wave, gate fixes, tracking) - #738
Conversation
…mode adopted, SME per-entry files, PR-body template+pr-scribe, lane-bootstrap), 3 rejections recorded
…e Opus 5 vs 4.8 worker A/B (item 18)
… with dated Tightenings changelog (ledger item 19) Operator directive 2026-08-08. First harvest: 11 entries from the 2026-08-07/08 lane rounds (PRs 615-621), incl. the validator env trap, the h3 section-parser bug, bun pass-count proof, rg -e, sed portability, guard workarounds, gates-read-the-database, clean-clone finish.
…ctive 2026-08-08) docs/sop-rlvr-lanes.md: the head-session loop, the parts table, measured why-it-works evidence from the first two runs, and the staged expansion path (repo norm -> second-repo pilot -> _DOCS/_ob canon). AGENTS.md gains an Operating Mode section so every future session meets it at the door.
…harvest of the #614 lane
…-stash trap, absolute-path CI death, control clauses for live checks, total-loss hypothesis, production-composition coverage
…ane report format, controller obligations with enforcement states (operator directive 2026-08-08)
…, deviations flagged, broken steps fail hard, hooks as last-ditch enforcement
…cwd trap, gitignore-by-outcome, no premature citations, done-means field live, canon on main
…t keeps round-3 harvest, graph/sop take the post-628 union
…sence defect (prove absence by the variable the code reads; re-run, never re-quote)
…eed runs on Sol, non-negotiable floor kept, loud one-way escalation
…ate removed, terra medium proven live; fast lanes may route Terra medium
…leness receipts, wall-clock flake class, gate word-match defect, effort-tiers-are-policy
…on, wrong-layer pattern, named-env residual risk
…ed reply + pointers, never whole-corpus single-shot)
… of 5-10 messages, never one payload
…ydration stamp, recall telemetry, drain-first outage)
…rsion pr-body-gate (#641), Sol runtime deaths, residual-risk flag
…rove RED after check edits, envelope-before-payload, #641 three-lane confirmation
…on-check negative matches, enum-before-dimension, closed-port outage pattern
…anding lane Two genuinely new lessons from _plans/worklog/land-artifacts-2026-08-10.md: - `rg -qF "$line"` parsed a diff-derived leading "-" as a flag and reported seven false MISSING lines during the pre-rebase superset check. Third spelling of the round-19 `rg -r` / `rg -E` family, so it is recorded as a standing class: `--` before any pattern that came from data, and `-F` does not imply it. The same reflex bit again during this harvest (`rg -h` is `--help`). Adds the corollary that a one-directional check whose verdict authorizes a drop or overwrite needs a positive control, because here the broken answer pointed at restoring stale graph content over newer root. - #710 and #712 were closed from the CLI, so their artifacts render "Closed without a pull request". That is the renderer being honest and it is the live argument that controller-contract obligation 2b is load-bearing: this repo's squash-into-wip flow frequently never creates GitHub's closing linkage, so the rationale has to live in a closure comment that the discussion mirror captures unconditionally. The #715/#712 lane's lessons (stderr not stdout, the reflex fix passing review, the deliberately unpinned bun byte threshold) were checked against round 29's #712 block and are already harvested there — not repeated. Review-facing half as an SME entry (lane gotcha-agent, order 71); lane files rebuilt via scripts/build-sme-indexes.ts. sme-per-entry-files.sh count pin 234 -> 235 with the reason inline; clause 1 remains RED for #707, which is not this harvest's file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… read (#714) (#718) #714's filed premise was stale: PR #713 (issue #709) already made the hook parse --head and set PR_HEAD_REF, so the branch tier is fed. Re-verifying it found a narrower residue that does reproduce. A branch NAME is not a ref until something can resolve it. `gh pr create --head <branch>` names a branch on the REMOTE, and run from a root checkout that has fetched but never created a local branch of that name -- no cd, no worktree -- the bare name resolves to nothing, so the tier was handed a dead string: git cat-file -e lane/x:scripts/done-means/check.sh -> fatal, exit 128 git cat-file -e origin/lane/x:... -> exit 0 The refusal then printed "; and in ref lane/x", which reads as "your check is not on the branch" when the truth is "that name means nothing here". A refusal that misdirects is worse than one that admits it looked nowhere: the cheapest way past it is a false receipt, which is the reflex the gate exists to prevent. resolvableRef() now tries the name as given first (so a correct ref, a SHA, or a local-only checkout is never mangled), then <remote>/<name> for each configured remote with origin first. Every candidate is asserted on POSITIVELY via rev-parse --verify (round 28), so a name resolving nowhere skips the branch tier rather than feeding it garbage, and the announcement names both what --head said and what actually resolved (AGENTS.md: nothing is adjusted silently). existsInRef's containment guard on the PATH is untouched: this widens WHERE a check may resolve, never WHAT may be named. Done-means: scripts/done-means/714-head-ref-resolves-remote.sh, 6 clauses driving the real hook with synthetic PreToolUse payloads against a GENUINE bare remote -- the defect is invisible in any fixture where the lane branch also exists locally, which is why 709-hook-feeds-head-ref.sh clause 3 passed throughout (round 28's false-green family). RED 3/6 before, GREEN 6/6 after; clauses 2/3/6 are controls that fail a bad fix and were green from the start.
…oks (#711) (#717) This clone's core.hooksPath was the ABSOLUTE path /Volumes/ThunderBolt/Development/open-brain/_githooks, while _githooks/install.sh:24 writes the relative "_githooks" under a comment written against this exact trap. The config had diverged from its own installer and nothing detected it: the installer reports "already set" only on an exact match, and no check asserted the value. .git/config is shared by every linked worktree, so an absolute value points every lane worktree at the PRIMARY checkout's hooks. That is the root of the #705-#714 family -- a lane fixing a git hook could not exercise its own fix on push, and a lane BREAKING one pushed green. Proven with a throwaway worktree and a marker line in each tree's copy: absolute + worktree -> primary's hook; relative + worktree -> its own hook; relative + primary -> unchanged. A relative hooksPath does resolve per-worktree. The config flip is per-clone state and cannot be committed (it was applied on this machine via ./_githooks/install.sh and is recorded in the journal). What ships is the detection: - _githooks/pre-push asserts the effective core.hooksPath matches the installer's value, before any validation and before the --explain exit, and fails the push naming the configured value, the expected value, and the install.sh command. Unset stays legal: git then uses .git/hooks and this file is not running at all. - _githooks/install.sh names the specific damage when the value it corrects was absolute. - scripts/lane-bootstrap.ts states which hooks the new worktree will run. - scripts/install-hooks.sh became a refusing stub: it set core.hooksPath to .githooks, which does not exist here, silently disabling every tracked hook. Done-means: scripts/done-means/711-hookspath-relative.sh (5/5 green; red before the fix was b/c failing with a/d passing as the mutation control). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Audited every gate/check that judges work in this repo against the #705-#714 family's two shapes (A: judging from the wrong tree; B: letting the environment decide the verdict). Ran each gate rather than reading it, on the untouched primary at 183d066. The five filed members are fixed and hold. Four new members are live: - #719 (B) core.hooksPath displaces the global gitleaks + protected-branch hook and _githooks/ ships no pre-commit, so secret scanning is silently off. The .git/hooks shim written to repair this is unreachable by construction. - #720 (A) validate-pr-body's OWN_TREE fallback passes a Done-means check that is absent from the branch under review, on the primary checkout's copy. - #721 (B) merge-gate-and-verify-lane.sh records its only live clause as PASS on any non-empty inherited MGVL_IN_VERIFY_LANE — exit 0, verify-lane unrun. - #722 (B) both pre-push done-means checks (705, 712) are RED on untouched main: fixtures inherit the global core.hooksPath and trip #711's assertion, then report it as substantive regressions that have not occurred. #722 is the one that matters most: the gate with the most family history currently has no working done-means coverage, and both blinded checks emit confident false regression text. Report carries the per-gate table, reproductions with positive and negative controls, and an explicit SOUND list (9 negative results) so the next audit does not re-litigate them. No fixes in this lane, per charter.
…ay not answer for it (#720) (#723) `OWN_TREE` was consulted as a plain second tree, BEFORE the branch under review was ever asked. The pr-body-gate hook runs the PRIMARY checkout's copy of the validator, so that tree is the integration branch — which has accumulated every done-means check ever merged. A check deleted from, renamed on, or never committed to the branch under review therefore PASSED on the strength of a same-named file in a tree that is not being merged, and the fallback fired most readily in exactly the case it should have caught. Family A (#706's own defect) one layer deeper, in the fallback. The rule now: the tree under review answers first, then the head ref. When a head ref is known those two are AUTHORITATIVE — their combined "no" is the answer, the own tree is not consulted, and the refusal says so. The own tree may answer only when no head ref exists at all (a human running the validator by hand), and that note names its weaker basis rather than reading identically to a branch-backed pass. Done-means: scripts/done-means/720-validator-rejects-foreign-tree.sh 7 clauses. Clause 5 drives the REAL path — a PreToolUse payload through .claude/hooks/pr-body-gate.ts with a genuine `gh pr create --head`, which the check's own RED run showed ALLOWING the foreign-tree citation end-to-end. Clauses 3/4/6 are the positive and regression controls; 7 is the mutant control. RED 4/7 pre-fix, GREEN 7/7 post-fix. 706 (5/5), 709 (5/5), and 714 (6/6) re-run green. 709 clause 4 asserts on the `looked in:` marker, so the new refusal keeps it verbatim rather than the assertion being moved to fit new wording. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…dc6be -> 8ef5271531d4) Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
…, forensics, lane E) Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
…placed (#719) (#727) `core.hooksPath = _githooks` REPLACES the operator's global hooks directory. Git consults exactly one directory; it never chains and never overlays. So `_githooks/` shipping only `pre-push` meant this repo had NO pre-commit hook, and the two controls the displaced global hook carried were silently OFF for every commit made here: - gitleaks staged secret scanning - LAW #8 — no commits on main/master/develop/production/staging Measured before the fix, in this lane's own worktree: $ git hook run pre-commit error: cannot find a hook named pre-commit # positive control, same tree, same command, the displaced path: $ git -c core.hooksPath=~/.config/git/hooks hook run pre-commit INF no leaks found The control is the finding: gitleaks was installed and working the whole time, and this repo's own config was the only thing stopping it. The `.git/hooks/pre-commit` shim whose docstring said it restored exactly this was unreachable — git ignores `.git/hooks` once core.hooksPath is set — so that repair was written and never once ran. Sweeping the WHOLE displaced set, as an override demands, found a SECOND live gap the issue did not name: the global `pre-push` also carried a gitleaks range scan and a default-branch push guard, and this repo's own `pre-push` replaced it carrying neither. Secret scanning was absent from BOTH ends of the commit path, not one. Changes: - `_githooks/pre-commit` (new): LAW #8 branch block, then a gitleaks `--staged --redact=100` scan. Fails CLOSED when gitleaks is absent, per _DOCS/STANDARDS-git.md. Announces every stage, because #719's failure mode is that an ABSENT gate and a PASSED gate look identical. - `_githooks/pre-push`: restores the displaced range scan and default-branch guard (keeping the global hook's ALLOW_DEFAULT_PUSH human escape hatch, so this does not silently become stricter than the rule it restores), placed BEFORE typecheck and the suite. - `_githooks/pre-push`: extends the #711 drift assertion so "hooksPath value correct, directory INCOMPLETE" warns and names the missing hook. #711 was 5/5 GREEN throughout this defect because it asserted the VALUE only. It warns rather than refuses: a wrong value corrupts this hook's own verdict, a missing sibling hook means a DIFFERENT gate is missing, and refusing a push over a defect it cannot cause is what trains `--no-verify`. - `_githooks/displaced-hooks-allowlist.txt` (new): dropping a displaced control becomes a decision someone wrote down, with a reason. - `scripts/done-means/719-hooks-dir-complete.sh` (new): 10 clauses driving REAL `git commit` and `git push` in fixtures configured exactly like this repo, with a fake canary (Stripe's published test value; never a real credential) and a paired control for every refusal. The controls are reimplemented in tracked files rather than delegated to the global hook: that path is absolute and machine-specific (#711's root enabler), untracked and unreviewable, and absent in CI and every fresh clone — so a delegating hook would degrade to no gate exactly where oversight is thinnest. Verification (all RUNNING this session): - 719 check: 10/10 GREEN post-fix; 7 of 8 clauses RED pre-fix. - 711 check: 5/5 GREEN, no regression. - Six mutants, applied and reverted one at a time: deleting pre-commit kills a/b/d/h; neutering only the commit-side scan kills b alone (while the hook still prints a green tick — the sharpest result); removing only the branch block kills d alone; neutering the push scan kills f alone; making the hook fail OPEN on a missing gitleaks lets the canary commit; removing the new completeness assertion kills i alone. Every control clause survived its siblings' mutants. Scope: this restores what the override displaced. It is deliberately not the full seven-check gate docs/CI_CD_REQUIREMENTS.md specifies as the eventual required state; that is separate work with its own cost budget.
…ited (#721) (#730) merge-gate-and-verify-lane.sh clause 9 is the ONLY clause that exercises verify-lane end to end. It skipped on the mere PRESENCE of MGVL_IN_VERIFY_LANE and recorded that skip as PASS, so MGVL_IN_VERIFY_LANE=1 bash scripts/done-means/merge-gate-and-verify-lane.sh exited 0 with every clause green and the live proof never executed. A stale export or a CI env leak silently disabled the check's only live evidence, and the transcript was indistinguishable from a genuine run. Family B of the 2026-08-10 gate-layer audit: a gate letting its environment decide the verdict. The guard itself is right — the recursion it prevents is measured (331 worktrees, 2026-08-08). The defect is that it was ASSERTED rather than EARNED. verify-lane.ts:479-480 exports both markers together and both are structured (MGVL_IN_VERIFY_LANE=pr-<n>, MGVL_VERIFY_LANE_PRS=<ancestry including n>), so the claim is now RE-DERIVED from the values: the marker must parse as pr-<n> AND <n> must appear in the ancestry. Shape alone is deliberately not enough — that would only replace one magic word with another. Also: - A skip is now recorded SKIP, never PASS, and a skipped live clause exits 4 (non-zero so it cannot read as proof, distinct from 1 so it cannot read as a regression). Follows issue-resolution-artifacts.sh's "skipped is not passed". - A polluted environment is exit 3 (HARNESS-ERROR), not a clause failure: "I cannot trust my inputs" and "the subject regressed" have different owners. - Sibling sweep: MGVL_LIVE_PR, the other inherited variable steering the live clause, was announced but never validated. Now refused when non-numeric or when it self-targets the PR containing this check. Verified this session (7/7 GREEN, and RED-first against the pre-fix subject at afc5525 where 6/7 clauses failed and the fabricated marker exited 0). Two negative controls: reintroducing skip-as-PASS is caught by clause 6, and weakening corroboration alone — invisible to clause 6 — is caught by clause 3. No CI workflow or sibling check consumes the exit contract, so exit 4 breaks no caller. Neutrality failures on this branch are pre-existing and identical on origin/wip/2026-08-07. Refs #721
…e code (#722) (#731) * checkpoint(#722): in-progress fixture hooksPath pin, salvaged from parked worktree (WRITTEN, untested) Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * fix(done-means): 712 clause (d) asserted on a path the fixture cannot pin (#722) The salvaged checkpoint pinned core.hooksPath in both fixtures and added the BLIND/HARNESS-ERROR guards, which took 705 from 5-of-6 FAIL to 6-of-6 PASS. 712 still failed clause (d) with the hook fully reached -- a real verdict, not a blind -- so the pin alone was not the whole defect. Clause (d) required the announced log path to sit under the fixture's own OPENBRAIN_TEMP_WORKSPACE ("$SCRATCH/ws"), set on the hook invocation by run_hook_through_pipe. The fixture cannot win that assertion, for the same reason #722 exists -- the ambient environment decides the verdict: env OPENBRAIN_TEMP_WORKSPACE=/probe/ws zsh -c 'echo $OPENBRAIN_TEMP_WORKSPACE' -> /Volumes/ThunderBolt/_tmp (the caller's value is discarded) env OPENBRAIN_TEMP_WORKSPACE=/probe/ws bash -c 'echo $OPENBRAIN_TEMP_WORKSPACE' -> /probe/ws The hook's shebang is `#!/usr/bin/env zsh`; ~/.zshenv is read by every zsh, including a non-interactive script, and it sources env-roots.zsh whose line 6 is an unconditional `export OPENBRAIN_TEMP_WORKSPACE=/Volumes/ThunderBolt/_tmp`. That overwrites what the caller passed, so the hook always logs to the operator's real temp workspace. Measured with a probe copy of the check: has_buntest=1, has_ws=0, announced path .../_scratch/pre-push/bun-test-*.log. So the old assertion tested the operator's shell profile, not the hook. The clause's stated subject is that the redirect is ANNOUNCED and the log NAMED; it now checks the announcement plus a concrete bun-test-<pid>-<epoch>.log filename. Pinning the DIRECTORY is not this check's business and is not something the fixture can do; pinning the SHAPE is, and it still fails if the hook stops naming the log. Mutation-tested: replacing the filename pattern with a sentinel the hook never emits makes clause (d) FAIL, so the clause is not vacuously green. Refs #722 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
…ad (#724) (#729) * test(done-means): gate the Aug 14-17 embedding backlog on recall, not on storage (#724) Adds scripts/done-means/724-backlog-recallable.sh, the red-first acceptance gate for #724 item 1. It is the reward function for the backlog fix, not a test of the fix's author, and it deliberately does not assert the shape the lane brief assumed. The brief located the backlog in ob_session_events. Measured against the live dogfood database while authoring, it is not there: 55 of 55 window events carry an embedding, and embedded_at equals created_at to within a millisecond, so embedding is synchronous on that write path. The gap in the window is in ob_session_lanes -- 2 of 2 eligible rows unembedded, against 549 all-time. Rather than hardcode whichever table happens to be short today, clause 1 reads src/embedding-targets.ts:EMBEDDING_TARGETS at runtime and checks every embedding-bearing table, using each target's own baseFilterSql for eligibility and its own namespaceColumn/namespaceVia for isolation. Holding a second copy of that list is precisely the defect class #433 documents, and the registry's filters matter: counting lanes with an empty topic would report 7,634 phantom window rows instead of 2. Clause 2 drives the real executeSearch from this checkout in BOTH keyword and semantic mode. Keyword search reads stored text and is structurally blind to a missing embedding, so a lexical-only probe would pass straight over the defect under test; the two arms disagreeing is itself the signature of stored-but-not- indexed rows. Clause 3 is the control: a known-good pre-window row must come back through the same path, so a dead service, an empty table list, or a broken embedding provider cannot fake a pass by returning nothing everywhere. A failed control exits 3, not 0 or 1 -- with the instrument silent the run has no authority to judge the window either way. Zero candidate rows examined is also exit 3, never a pass. Two instrument defects were found and fixed while establishing red, both of which had made the gate lie about a healthy path: - The probe subjects were left(content, 60) of the newest rows, which yielded boilerplate ("Recorded codex turn checkpoint for Development. 3. Self-host") truncated mid-word and shared by thousands of rows. All 25 keyword hits were different rows carrying the same prefix. Subjects are now excluded from the known boilerplate and cut on a word boundary. - The window boundaries were resolved in local time by SQL and in UTC by the probe. The control row at 2026-08-14T02:55:40Z is Aug 13 21:55 local: SQL called it pre-window, the probe called it in-window, and the control reported zero hits while nothing was broken. Both halves now take boundaries computed by Postgres in one session zone. Observed this session (RUNNING): exit 1 with clause 1 FAIL on ob_session_lanes, clause 2 PASS, clause 3 PASS. Exit 3 confirmed against an unreachable database. Whether the nats-worker outage caused the unembedded lanes is unverified by this gate; it observes the rows, not the cause. No fix is included. Refs #724 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * fix(embeddings): give the repair primitive the bulk caller it never had (#724) The Aug 14-17 backlog did not drain because nothing enqueues embedding repair. docs/embedding-repair.md states the boundary outright: the maintenance bootstrap starts the embedding.repair runner but "invents no namespace and enqueues no job" -- enqueue is deliberately an explicit, auth-scoped caller boundary. No caller occupied that position for a bulk historical backlog: maintenance-sweep enqueues only distill and graph derivation, and scripts/backfill.ts covers only the five original domain tables, which excludes ob_session_lanes where the window gap actually was. Measured on the dogfood database rather than assumed: eligible-but- unembedded ob_session_lanes held at 549 across four minutes with zero maintenance_jobs activity, and no embedding.repair job has ever been recorded. The runner was healthy and correctly idle. scripts/repair-embeddings.ts occupies the missing caller position and nothing more. It adds no pipeline, no table, and no SQL: it loops repairStaleBatch (src/embedding-repair.ts:682), whose own docstring says it is for script-style bulk runs, over EMBEDDING_TARGET_NAMES read at runtime so the table list cannot drift into a second copy. Namespace scope is mandatory and explicit. Two behaviors are measurement-driven, not preference: Selection asks for the "missing" reason alone. buildSelection ORs every reason into one unordered SELECT ... LIMIT n, and the source_drift arm matches rows that already have an embedding, so an all-reasons batch is crowded with non-repairable rows and, with no ORDER BY, need never converge. Restricting to "missing" makes every selected row repairable, which is what makes repaired == 0 a truthful stop condition. A per-table failure no longer aborts the run. The first global run died on a leaked test fixture still live on the dogfood database: a BEFORE UPDATE trigger on thoughts that RAISEs on every update. That trigger is a separate defect and is not dropped here; the loop simply refuses to let it hide the other tables' backlogs, and reports it in the exit code. Run result: 1,627 rows repaired across five tables; eligible-but- unembedded ob_session_lanes went 549 to 0. The done-means check moved from exit 1 (clause 1 FAIL, 2 of 2 window lanes unembedded) to exit 0 with all three clauses passing. Residual, filed in the worklog and not closed here: the leaked trigger blocking 1,297 thoughts rows, unique-constraint collisions blocking the sessions drain, and the fact that nothing yet schedules this CLI. Refs #724 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX --------- Co-authored-by: Rodaddy <rico@rtech-consulting.com>
…#724) (#728) * test(nats-worker): red done-means for embed watermark on worker health (#724) Nothing alarms when the maintenance producer ticks with no consumer. Raw rows keep arriving, embedded rows stop, and every liveness surface stays green -- observed as three silent days. A watermark comparison (newest embedded-row age vs newest raw-row age, with fresh raw rows present as the guard) would have caught it in about an hour. This is the RED half only. It asserts the desired `embed_watermark` block on the NATS worker's own /health (port 3110), composed by startHealthServer in scripts/run-nats-worker.ts:83-113. The surface belongs there and not on 3100: docs/core01-nats-worker-runbook.md ("What /health on 3100 does and does NOT show") records that the HTTP service derives its blocks from its own process environment and deliberately never observes the worker process, and forbids putting the worker back into the HTTP service's business. Naming matches the existing convention rather than inventing one: server/transport/health.ts:14-33 and :35-79 establish the snake_case liveness block with a boolean `stale` verdict, raw counters beside it, an explicit `*_threshold_*`, and a content-free `reason`; src/operator-doctor.ts:111 establishes `*_age_seconds` for an age. Absence-is-not-staleness is asserted too, matching the optional `maintenance_producer` and `capture` blocks at server/transport/health.ts:93-105. All ages are fixture data and the clock is injected; no wall-clock sleeps or comparisons (docs/lane-contract.md, Tightenings round 5). RED (observed this session, bun run test:isolated on this file): 4 fail, 1 pass. The single pass is the absence control, which is correct on current code -- no observer is composed, so no block appears and the worker stays healthy. The four failures are the missing fields and the missing verdict: - carries the embed watermark ages ... -> Received: undefined - CONTROL current watermark healthy ... -> body.embed_watermark undefined - flips off healthy when lagging ... -> Expected "degraded", got "healthy" - stale requires FRESH RAW ROWS ... -> body.embed_watermark undefined bunx tsc --noEmit: clean. No implementation in this commit. Refs #724 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * feat(nats-worker): surface embed watermark liveness on worker /health (#724) The maintenance producer ticked for three days with no consumer draining the embed queue. Raw rows kept arriving, embedded rows stopped, and nothing anywhere COMPARED the two -- every liveness surface stayed green while the corpus quietly stopped being searchable. Add an optional `embed_watermark` block to the NATS worker's /health on 3110, composed by startHealthServer. `stale: true` flips status to degraded/503 even when the bridge is available, so a healthy bridge cannot mask a stalled embed lane. The block matches the shape the producer (#625) and capture (#647) liveness blocks established at server/transport/health.ts:14-33 and :35-79: snake_case named block, boolean `stale` as THE verdict, raw counters beside it, an explicit *_threshold_* naming the bound used, and a content-free `reason`. `*_age_seconds` follows src/operator-doctor.ts:111. Injection matches the optional-input pattern at server/transport/health.ts:118-138; degradation matches :185-196. Absence is not staleness: a worker composing no observer emits no block and cannot be degraded by one. `stale` additionally requires `raw_rows_recent > 0` so an idle corpus does not alarm. Threshold: OPENBRAIN_EMBED_WATERMARK_LAG_THRESHOLD_SECONDS, default 3600. Nothing adjusted silently -- the startup log announces the value, its source (default/env/invalid_env_default), and whether an observer is composed. Sited on 3110 rather than 3100 per docs/core01-nats-worker-runbook.md ("What /health on 3100 does and does NOT show"), which forbids putting the HTTP service back in the worker's business. Refs #724 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * test(done-means): bash wrapper so #724's check runs under verify-lane (#728) scripts/verify-lane.ts:473 executes every Done-means check with `bash`, so #724's acceptance — a bun test file, scripts/run-nats-worker-embed-watermark.test.ts — cannot be named directly in a PR body and the merge gate for #728 could not pass. That runner limitation is filed separately as #733; this adds the bash-shaped front door rather than changing the acceptance itself. The wrapper runs `bun run test:isolated` on that one file and maps outcomes to the repo exit grammar: 0 green, 1 the thing under test failed (tests red, or exit 0 with zero tests executed — a silent skip is not a pass), 3 harness error for bun missing, a missing `test:isolated` entry point, an unreadable .env, or a database bootstrap that never named a database or reported a tally. A broken harness is not a red result and must not be reported as one. It fails loudly at exit 3 when the acceptance FILE is absent from the tree: zero files examined is the failure mode that would otherwise read as a pass. .env resolution falls back to the canonical checkout the same way 614 does, so the check runs from a lane clone or worktree that carries no .env of its own. Observed this session on this tree: exit 0, 5 pass / 0 fail against isolated database ob_isolated_80153_msy175db07; and exit 3 with the loud message when the acceptance file is moved aside. Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX --------- Co-authored-by: Rodaddy <rico@rtech-consulting.com>
…me-namespace client test retired (operator rulings 2026-08-17) Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
* test(runtime): red-first proof that wrap must adopt an existing capture lane's scope (#724) Reproduces the manual wrap/checkpoint failure exactly: a lane created by the capture hook (agent='openbrain-capture', all other exact-scope fields NULL) is wrapped from a runtime scoped as a different agent, and session_start is refused with 'existing lane exact scope does not match session_start request'. Asserts the POST-fix behavior per the operator ruling 2026-08-17: wrap adopts the lane's stored scope, session_start for a wrap binds on session_key + namespace only, the write verb carries the LANE's scope, and the lane is never re-pointed. The server-side one-way fill is an isolation boundary and is not changed by this lane. RED on this commit: 6 failed, 1 passed. No fix applied. Refs #724 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * fix(runtime): manual wrap adopts an existing lane's scope instead of claiming its own (#724) A manual `openbrain-memory --event wrap` (and `--event checkpoint`) against a lane the capture hook opened failed with `Existing lane exact scope does not match session_start request`, losing two Development sessions' wraps. The capture hook creates the base lane with `agent` set and every other exact-scope coordinate NULL; the client made `session_start` claim the CALLER's full exact scope, which trips the server's #646 one-way fill. Operator ruling 2026-08-17: the wrap adopts the lane's scope. The server's refusal is an isolation boundary and does not move -- `server/` and `src/` are untouched here. The client is what stops asserting a scope it does not own. Claim first, adopt only on that specific refusal: 1. `session_start` claims the caller's own exact scope, exactly as before. On success nothing else changes -- same single call, same arguments -- so the ordinary path is byte-for-byte unchanged and adoption costs nothing until it is needed. 2. Only on the scope refusal, re-issue `session_start` claiming nothing but `session_key`. That is the server's `!hasCompleteExactScope` branch, which returns the existing lane verbatim instead of attempting a fill. 3. `session_wrap` then carries the coordinates that came back on that lane, not the requester's, because the write verb must still satisfy the server's lane-scope predicate. Adoption is not "send fewer fields on start". Discovering unconditionally was tried first and is wrong twice over: on a lane that does not exist yet it CREATES a bare NULL-scoped lane and strands it, and it adds a wire call to the sequence the cross-runtime contract fixture pins. `validate_adopted_lane` binds the adopting start on `session_key` + `namespace` -- the coordinates the caller genuinely owns -- because there is no requested exact scope for the response to prove. The namespace refusals (#654/#662) are extracted into `_require_proven_namespace` and enforced unchanged on both paths rather than copied. Nothing else is widened: capture (`append_session_event`) and the context-pack exact-scope proof are untouched, and the adopting flag is scoped to the single discovery call so a spooled session_start replay still proves its own parked scope. Two fidelity gaps in the test fakes are corrected, both toward the real server: `LaneAwareTransport` now mirrors the `hasCompleteExactScope` gate (it had only the refusal half, so it refused a request the server accepts), and `StartThenFailClient` reads exact-scope coordinates with `.get()`, matching the server schema where all of them are `.optional()`. DEVIATION, needs a ruling before merge: `test_checkpoint_first_lane_denies_hostile_same_namespace_claim` now fails. It is not collateral -- it is the ruling's direct consequence. Verified by driving both cases through the fake: the client emits an IDENTICAL request sequence whether the stored lane belongs to the capture hook or to another session in the same namespace. Only the server's stored lane differs, so no client-side signal distinguishes them. Adoption and that assertion cannot both hold. The test is left failing rather than deleted or weakened, because relaxing an isolation assertion is not an implementer's call. Refs #724 Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * test(runtime): retire the hostile same-namespace claim test per operator ruling (#724) Operator ruling (Rico, 2026-08-17): with wrap-adopts-lane-scope (the #724 item-4 fix on this branch), the client provably cannot distinguish the capture hook's lane from another same-namespace session's lane -- the wire sequences are identical, which the lane proved. There is nothing observable left for test_checkpoint_first_lane_denies_hostile_same_namespace_claim to assert on. Same namespace is the same tenant. The boundary that matters is the server's namespace predicate, and AGENTS.md Coding Standards already state that client-side convenience checks are not security controls. A comment stands at the test's former site naming the ruling date and the reason, so the next reader knows it was retired rather than lost. docs/memory-contract.md now says in one sentence that wrap/checkpoint adoption is namespace-scoped by design. Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX * test(done-means): add a bash front door for the wrap-lane adoption pytest file (#724) `scripts/verify-lane.ts` runs every Done-means check with bash, so the pytest acceptance file for wrap-lane adoption cannot be named directly in a PR body. This wrapper runs it and maps the result onto the repo exit grammar: 0 green, 1 red, 3 harness error. The harness tier explicitly covers uv missing, dependencies unresolvable, and the test file being absent — zero files examined is never reported as a pass. Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
…ark observer (#724) (#737) * test(nats-worker): red-first proof the LIVE worker composes no watermark observer (#724) #728 landed the embed-watermark health surface on the NATS worker and proved every part of it by INJECTING an `embedWatermarkHealth` option. Nothing constructs one. `startNatsWorkerProcess` only forwards `options.embedWatermarkHealth` (scripts/run-nats-worker.ts:333-335) and the live entrypoint calls it with `{ env: process.env }`, so the deployed worker logs `embed_watermark_observed: false` (:345), publishes no `embed_watermark` block, and can never alarm — the surface is in the tree and absent from the serving process (#674 class; #656 caught the identical shape for capture). Adds the acceptance gate only, not the fix: - scripts/run-nats-worker-live-watermark.pg.test.ts starts the worker the way the deployed process does (NO watermark option) against a real pool on the isolated test database, seeds `thoughts` rows at explicit ages, and asserts the startup summary reports an observer AND that /health carries a block computed from those rows — stale+503 past threshold, healthy within it, healthy-with-numbers on an idle corpus. - scripts/done-means/724-watermark-live-observer.sh is the bash front door (verify-lane runs checks with bash, #733), exit grammar 0/1/3, and fails a 0-pass exit 0 so a silently-skipped dbDescribe cannot read as green. A real database is load-bearing: the failure mode guarded is an observer returning plausible numbers not derived from rows, which a fake pool would let pass. `thoughts` is EMBEDDING_TARGETS' first entry under FULL_PROVENANCE (src/embedding-targets.ts:181,191), so `created_at` is the raw watermark and `embedded_at` the embedded one from one table. RED as written: 4 tests, 4 failures, each on the gap itself (`embed_watermark_observed` false / block undefined), none on harness noise. Refs #724 * feat(nats-worker): the deployed worker composes its own embed watermark observer (#724) PR #728 built the whole embed_watermark health surface and proved it by INJECTING the reading. Nothing constructed an observer, so the deployed worker logged embed_watermark_observed: false, published no block, and could never alarm -- the surface was in the tree and absent from the serving process. Same class as #656 (capture observer wired). startNatsWorkerProcess now default-constructs an observer against its own pool when the caller supplies none; the option stays an override so #728's fixture test is unchanged. The live entrypoint still passes only { env: process.env }. The watermark is registry-driven: every EMBEDDING_TARGETS entry whose provenance.hasEmbeddedAt is true (src/embedding-targets.ts:146-150,326), the same registry the embedding repair path drives off. ob_entities is skipped on ENTITY_PROVENANCE (:158-162) rather than queried for a column it lacks. The health handler is synchronous, so the accessor never queries: it serves a cached reading and schedules a background refresh past a 30s TTL, announced at startup as embed_watermark_cache_ttl_seconds beside the threshold. A read failure composes stale: false with a reason naming the failure and the last good numbers (-1 when never measured) -- a database the observer cannot reach is evidence about the observer, not the lane -- and can neither crash /health nor hold a silent green. Done-means: bash scripts/done-means/724-watermark-live-observer.sh before wiring: 0 pass, 4 fail after: 4 pass, 0 fail 38 pass across the worker + registry suites; bunx tsc --noEmit clean. Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX --------- Co-authored-by: Rodaddy <rico@rtech-consulting.com>
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 35895816 | Triggered | PostgreSQL Credentials | 28fe9d9 | src/observability/observability.test.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Two integration lines had advanced in parallel (main: #686-#691/#701/#726; wip: #708-#737). Resolutions, all announced: lane-contract Tightenings kept as a UNION with a fork note (rounds <=29 are per-line); sme-per-entry-files pin re-measured on the merged tree per round 28's own rule, both provenance trails kept; docs/sme/gotcha-agent.md REGENERATED from entries (never hand-merged) after renumbering three forked order collisions (72/73/74). Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
…counts (#707); pin 241 -> 242 same commit Claude-Session: https://claude.ai/code/session_01U3sT5FabVFHQwwfqKVXFjX
|
verify-lane receipt: check=scripts/done-means/724-wrap-lane-adoption.sh exit=0 sha=19df06617f8747e16e4dbaf772b0a96a62f56b16 at=2026-08-18T13:04:59.569Z check output (tail)Posted by |
Summary
Verification
Every lane PR in this range merged behind an independent verify-lane receipt bound to its head SHA plus the enforced harvest gate; per-PR receipts live on PRs #727-#732 and #737. The wave is RUNNING on the local dogfood runtime: revision bf5e4d3 deployed with revision-proof, 3110/health serving the embed_watermark block from the live DB, live manual wrap saved+durable against a hook-owned lane, window-content recall verified in both search arms.
Critical Self-Review
Review Gate
docs/sme/or explicitly marked not applicableContract Parity
Downstream Rollout
docs/downstream-rollout.mdNotes/evidence: