Skip to content

fix: eight adversarially-confirmed bugs from an engine hunt - #111

Merged
ElxMaj merged 1 commit into
mainfrom
fix/engine-hunt-bugs
Jul 19, 2026
Merged

fix: eight adversarially-confirmed bugs from an engine hunt#111
ElxMaj merged 1 commit into
mainfrom
fix/engine-hunt-bugs

Conversation

@ElxMaj

@ElxMaj ElxMaj commented Jul 18, 2026

Copy link
Copy Markdown
Owner

An adversarial bug hunt over the shipped engine (a finder per high-risk module, each candidate then refuted-by-default by an independent verifier) surfaced ten real defects. This PR fixes the eight with clear, low-risk fixes and a regression test each. Two are deferred to focused follow-ups (see bottom).

Fixes

Sev Where Defect Fix
high scrub.ts Stripe underscore keys (sk_live_/sk_test_/rk_live_) bypassed the sk- rule and reached immutable evidence in plaintext (sacred rule 1). Sibling detector for the underscore family.
medium sync.ts An idle sync run fell back to the local wall clock instead of the prior watermark, silently dropping items that became visible after the run. Retain the cursor; only the first-ever run falls back.
medium transcripts.ts A VTT cue whose spoken text began NOTE/STYLE/WEBVTT was dropped as a comment block. Track cue state; skip comments only between cues.
medium store.ts Entity merge left goal.entity_id dangling, so deleting a goal-referenced entity tripped the FK and rolled back the whole distill. Re-point (or detach) the goal alongside edges and verifications.
medium link.ts codeMatchesTerm / decisionsConcerningEntity matched substringssync in async, auth in author — raising false drift questions and forging bogus concerns edges. Match whole identifier words, splitting camelCase and snake_case.
low cli.ts --hops / --depth weren't value flags, so a flag before the node id made the parser read the number as the id. Add them to the value-flag set.
low api.ts A non-positive/fractional limit reached SQL as a negative LIMIT and 500'd. Fall back to the default.

Verification

Six new core tests + one server test, each reproducing its bug. pnpm typecheck, pnpm lint, root pnpm test (ℹ fail 0; core 366, web 117), pnpm smoke:packed, and check-benchmark-drift all green.

(Note: the scrub test fixtures are built by string concatenation so the file carries no contiguous key literal for push-protection scanners.)

Deferred to focused follow-ups (both confirmed, both mitigated)

  • Distill embedding reconcile (medium): a transient embedNode failure after the row commits leaves a node without an embedding, and the idempotent re-distill skip makes it permanent. Needs an atomicity/backfill design with keyless-mode care; mitigated today by the keyword fallback in runSearch and edge-only graph neighbors in prepareTask.
  • API error-message echo (low, security): the classifier echoes raw messages matching /invalid /, so a bad timestamp param can reflect a Postgres error. Needs boundary date-validation across endpoints.

🤖 Generated with Claude Code

An adversarial bug hunt (fan-out finders, refute-by-default verify) over the
shipped engine surfaced ten defects; these are the eight with clear, low-risk
fixes and a regression test each. Two are deferred to focused follow-ups (a
distill embedding-reconcile that needs atomicity/keyless care, and an API
error-message-leak that needs boundary date validation).

- scrub.ts (sacred rule 1, high): Stripe underscore keys (sk_live_/sk_test_/
  rk_live_) bypassed the sk- rule and reached immutable evidence in plaintext.
  Added a sibling detector.
- sync.ts (data loss): an idle sync run fell back to the wall clock instead of
  keeping the prior watermark, silently dropping late-visible items. Retain the
  cursor; only the very first run falls back.
- transcripts.ts (data loss): a VTT cue whose payload began NOTE/STYLE/WEBVTT
  was dropped as a comment. Track cue state; skip comments only between cues.
- store.ts (data integrity): entity merge left goal.entity_id dangling, so
  deleting a goal-referenced entity tripped the FK and rolled back the distill.
  Re-point (or detach) the goal alongside edges and verifications.
- link.ts (correctness): codeMatchesTerm and decisionsConcerningEntity matched
  substrings (sync in async, auth in author), raising false drift and forging
  bogus concerns edges. Match whole identifier words, splitting camelCase/snake.
- cli.ts: --hops/--depth were not value flags, so a flag before the node id
  made positional() read the number as the id.
- api.ts: a non-positive/fractional limit reached SQL as a negative LIMIT and
  500d; fall back to the default.

Six new core tests + one server test; typecheck, lint, root test (fail 0),
smoke:packed, and benchmark-drift all green. Patch changeset (core+cli+web).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f038a41cda

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/link.ts
* never a substring: "sync" no longer matches "async", "test" not "latest",
* "auth" not "author". */
function codeTokens(code: string): Set<string> {
return new Set(words(code.replace(/([a-z0-9])([A-Z])/g, "$1 $2")));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Split initialism boundaries in code tokens

When a relevant code identifier contains an initialism, this tokenizer leaves the initialism and following PascalCase word fused: for example, parseHTTPResponse becomes parse, httpresponse, so a decision such as “no HTTP responses” produces the responses/response variants but neither is present in codeWords. The prior substring fallback detected these common identifiers; add acronym-to-word boundary handling (such as HTTPResponseHTTP Response) so the whole-word fix does not silently miss drift signals.

Useful? React with 👍 / 👎.

Comment thread packages/core/src/link.ts
Comment on lines +296 to +297
const decWords = new Set(words(`${decision.title} ${decision.rationale}`));
return terms.some((term) => decWords.has(term));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match plural entity references as whole words

This exact-token check drops ordinary singular/plural references: an entity named password no longer matches a decision saying “no passwords,” even though the previous matcher did. In that case entityHasDecision returns false, which prevents the intended concerns edge and raises a spurious gap question. Check the existing whole-word variants(term) (or equivalent inflection variants) against decWords to retain this relation without reintroducing substring matches such as auth in author.

Useful? React with 👍 / 👎.

@ElxMaj
ElxMaj merged commit e18279e into main Jul 19, 2026
2 checks passed
@ElxMaj
ElxMaj deleted the fix/engine-hunt-bugs branch July 19, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant