Skip to content

release: v1.6 hardening — bounded imports, fleet hygiene, fail-able eval gates - #159

Merged
Coding-Dev-Tools merged 27 commits into
mainfrom
release/v1.6-hardening
Aug 23, 2026
Merged

release: v1.6 hardening — bounded imports, fleet hygiene, fail-able eval gates#159
Coding-Dev-Tools merged 27 commits into
mainfrom
release/v1.6-hardening

Conversation

@Coding-Dev-Tools

Copy link
Copy Markdown
Owner

Summary

  • Bounded uploads: wizard multipart parsing under advertised MAX_IMPORT_FILES=1500 ceiling (clean 413 oversize), batch ceilings 500→1500 files / 750 MB with lockstep document/Obsidian scanner budgets, truncation surfaced (truncated/matched_total/unreadable), per-file failure isolation, worker-dead import jobs marked failed on poll.
  • OneDrive Files-On-Demand placeholders hydrate via fsutil.is_link_indirection; symlinks/junctions stay blocked.
  • Sync/MCP reliability: stateless standalone HTTP transport (no orphaned sessions), keyset pagination for source-import manifests, sqlite-vec visibility batch 8→500.
  • Eval gates made fail-able (floors + exit codes): grounded/ablation/code_arm wired into CI; new eval/code_arm.py proving the code arm.
  • remember_many batch writes with within-batch resolution; consolidate same-tick deferral + non-degenerate archive windows under coarse clocks.
  • Fleet hygiene: integrations/hermes/ withdrawal (fresh main checkouts no longer resurrect it), CodeQL atomic action bumps, root-artifact gitignore rules.
  • Reasoning-model LLM budgets (thought synthesis 4096, ping 1024).

Verification

  • Full offline pytest suite green (with ENGRAPHIS_EXTRACTOR=none); ruff clean; commercial manifest OK; externalize_dashboard_assets CSP OK; pyright core+backends 0 errors.
  • Evals at last full run: nDCG 0.918–0.972, grounded abstain 5/5, code_arm PASS.

Notes

  • Fast-forwarding main was owner-approved but blocked by branch protection (9 required checks) — this PR is the compliant path. main is a strict ancestor; merge type preserves history either way.

…, CI wiring

eval/harness.py gains a per-dataset floor registry (sample/codemem >= 0.9
recall/hit at k=5) enforced by main() with exit 1; grounded.py now gates on
decision accuracy == 1.0; ablation.py exits non-zero on violated invariants.
ASCII-safe harness output plus the previously omitted mrr/ndcg lines.
ci.yml runs the grounded + code-arm gates and adds the codemem step to the
py39 floor lane; AGENTS.md section 1 and its documentation-contract test stay
pinned together.
New deterministic offline eval proving the code retrieval arm reaches
call-bridge answers that vector and lexical arms cannot (arm-isolated
recall@5: vector 0.0, lexical 0.0, code 1.0; pipeline balanced 0.0 vs
code 1.0). Bridges form only via index_repo + write-time memory-code
linking; distractors carry the query's surface words so text arms fill
top-k with near-misses. Exit 1 without strict lift.
… notice

scripts/cli.py maps sqlite3/OSError/ImportError/RuntimeError from service
startup to one redacted actionable line instead of a traceback;
scripts/consolidate.py --db now defaults to settings.db_path like every
other entrypoint; engraphis-init prints an explicit notice when pinning
the trusted config to a CWD-relative database path.
engraphis-sync console script plus 'engraphis sync' verb route to
scripts.sync:main; new --status prints local-only sync state (device,
generation, state hash, counts, configured remote/relay) read via a
read-only SQLite URI — no network I/O, no mutation, nothing fabricated.
Entry-point smoke manifest stays pinned to pyproject.
…edger sizes

sqlite-vec visibility post-filtering now batches ids at IN_CLAUSE_CHUNK
parity (500) instead of 8, removing ~60x SQL round-trip amplification on
filtered native search. Auto-mode fallback to the NumPy index logs one
warning naming both backends. Recall capabilities gain additive
vector_index_backend / reranker_mode keys; stats() reports
operation_receipts/events/audit row counts so append-only ledger growth
is observable.
…build

_repair_conflicts logs and audits conflict-detection failures instead of
silently disabling repair; consolidation safety-label inheritance writes an
audit row like every engine-side sensitivity change; memories_mentioning
gets a bounded SQL window against sparse-eligibility full-repo scans;
embedding rebuild pages only rows missing or stale in mem_vectors so
interrupts resume instead of restarting; duplicated graph-arm entity seeding
extracted into one helper; dead RecallEngine._pack shim removed; Store now
asserted against the exported LexicalIndex protocol.
… warning

sync dict_to_record validates workspace_id/repo_id symmetric with every
other clamped field (both are re-homed locally, so this is hardening only);
http_security logs one startup warning when ENGRAPHIS_CSP is explicitly
emptied so a CSP-less deployment is observable.
CHANGELOG [Unreleased] records the source-import hardening landing via
#154 (deterministic missing detection, denial-guard supersession,
generation-guarded finalization, keyset manifest paging, constant-time
finalized check). Skills reference documents the fast retrieval profile
and every engraphis_answer parameter; update-check docs state the opt-in
default the code actually has; README gains ENGRAPHIS_UPDATE_CHECK/_URL
rows, the new sync CLI surface, and the facade note; ARCHITECTURE_V3
qualifies schema-3 as historical; SYNC.md documents the shared-folder
workspace_name residual risk and append-only ledger growth. Skill-asset
manifest re-pinned; offline evidence artifact re-issued binding the
edited eval/grounded.py (numbers unchanged) across all pinned surfaces.
Removes integrations/hermes/ (provider plugin + README), its integration
test, the README Hermes-provider section, and the packaging test's
plugin-version pin. Files are archived locally under
_archive/engraphis-hermes-integration-20260821/ and remain recoverable
from v1.5 release history. CHANGELOG [Unreleased] records the withdrawal.
The negative guard asserting other integration surfaces stay Hermes-free
(test_packaging) is retained.
FactSpec batch assembly in MemoryEngine.remember_many: one shared
transaction, each fact resolved against already-resolved siblings
(NOOP-reinforce on near-duplicates, keyed supersession), atomic
rollback on any failure, and evidence-labeled related edges between
siblings sharing a subject_key or declared provenance source.
MemoryService.remember_many wraps it with shared-batch provenance and
a 500-item cap; exposed as MCP tool engraphis_remember_many (classic
surface 34 -> 35 tools) with docs, skill reference, and asset hashes
synchronized. New tests/test_remember_many.py covers ordering,
within-batch dedup/supersession, evidence wiring, rollback, caps.
…zero-width validity window

Windows clock granularity (~15.6 ms ticks) can tie a memory's creation
stamp to the sweep's `now`, collapsing [valid_from, archived_at) to an
empty half-open interval that no as_of read can see; the test then fails
~60-70% of runs depending on host timing. Back-date creation and advance
the sweep instant so the assertion exercises archival semantics, not
host clock granularity. Complements the consolidate-side non-degenerate
close clamp for degenerate caller timestamps.
… coarse clocks

A consolidation sweep whose now ties a memory's ingest instant (~15.6 ms
Windows clock ticks) closed [valid_from, valid_to) to zero width, making
the archived row invisible to every as_of read — including the historical
recall archiving exists to serve. Clamp the archive close instant to
valid_from + 1us when now <= valid_from; the store-level close contract
for exact caller-supplied instants is untouched.
Windows wall-clock resolution can tie _mark_authoritative_denial to the
reconnect bootstrap's entitlement_checked_at, so the strict > in
_clear_superseded_denial never fires and the guard sticks. Back-date the
denial stamp so the test asserts supersession logic, not host clock
granularity.
…dow width

A sweep whose now ties a memory's ingest instant (~15.6 ms Windows clock
ticks) cannot separate 'live' from 'historical': closing [t, t) hides the
fact from every as_of read, while clamping valid_to forward (valid_from +
1us, the previous approach) leaves the just-archived row live-visible to
every read sampling the remainder of the same tick — observed as an
intermittent failure of test_consolidate_archives_decayed_transients_but_
not_pinned (~1/8 module runs).

Defer instead: the tied sweep leaves the memory live and reports it via
report['archive_deferred']; a strictly later sweep closes it with ordinary
half-open semantics. Production sweeps run minutes apart, so deferral is
unobservable there. Tests asserting closed-path archives now back-date
valid_from deterministically rather than racing the host clock.
…rphan sessions

FastMCP's default stateful streamable-HTTP mode tracks session ids in
memory, so every engraphis-mcp-http bounce (pm2 resurrect, watchdog,
manual restart) invalidated all live sessions: the client's next request
got a 404, the mcp SDK raised 'Session terminated', and Hermes gateway
clients parked for their full 300s retry interval with zero registered
tools (60+ such restart cycles in hermes-logs/engraphis-mcp-http.log).

Set stateless_http on the standalone launcher's server so every POST is
self-contained per the MCP spec; spec-compliant clients skip the absent
GET SSE stream (405). stdio and dashboard mounts keep their defaults.
- dependabot.yml: group github/codeql-action/* so init+analyze always bump
  in one PR; a mixed-version pair deterministically fails CodeQL's analyze
  post-action step (seen on open dependabot #157/#158)
- .gitignore: schema-migration flock (.*.migration.lock, held live while
  the server runs) plus regenerable root-level diagnostic dumps
  (/404_paths.txt /disk_report.txt /large_files.txt /stats_pm2.txt
  /venv_status.txt /r3.txt)
… an LLM extractor

MemoryService picks up the owner's ~/.engraphis/config.env, so on machines
with ENGRAPHIS_EXTRACTOR=llm every engine.ingest() call in the suite made a
live extraction request (10-90s through the local proxy). That starved
test_session_close_linearizes_before_delayed_memory_write[ingest]'s 10s
worker budget and made the 'offline gate' network-dependent.

Force ENGRAPHIS_EXTRACTOR=none via os.environ.setdefault, mirroring the
existing ENGRAPHIS_UPDATE_CHECK=0 posture: real shell overrides still win
(config.env itself uses setdefault), and tests exercising extraction opt
in explicitly. Idempotent file: 41s+ with live calls -> 8.9s offline.
- Raise MAX_IMPORT_FILES 500 -> 1,500 and total bytes to 750 MB; document/Obsidian scanner budgets move in lockstep.
- Parse dashboard wizard uploads through _BoundedUploadRoute under the advertised ceiling: >1,000-file batches no longer fail inside Starlette's hidden 1,000-part default; oversized batches return a clean 413 and large vault uploads clear the 8 MB body limit.
- Surface folder-import truncation via truncated/matched_total/unreadable instead of silently importing an alphabetically-first slice.
- Degrade one unreadable/pathological file to a per-file error instead of rolling back the whole batch with a 500.
- Mark worker-dead import jobs failed (worker_lease_expired) on next status poll instead of reporting running forever.
- Hydrate OneDrive Files-On-Demand placeholders via new fsutil.is_link_indirection; symlinks and junctions remain blocked.
Thought synthesis default 512 -> 4096 tokens and availability ping 5 -> 1024: reasoning models spend completion budget on hidden reasoning tokens first, so tiny caps returned empty replies that read as false negatives.

@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: c23d6d5ed7

ℹ️ 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 engraphis/core/engine.py
Comment thread engraphis/core/engine.py Outdated
Comment thread engraphis/service.py Outdated
Comment thread engraphis/core/recall.py
Eval fixtures seed via tempfile.TemporaryDirectory(), which lands under the runner tempdir — not under GITHUB_WORKSPACE/RUNNER_TEMP roots exported to pytest legs, so index_repo rejected them ('repo root is outside approved local roots'). Append tempfile.gettempdir() to ENGRAPHIS_INDEX_ROOTS on the three full-suite legs.
…oad test

- test_service: staticmethod wrapper is not callable on 3.9; patch the module attribute with a plain callable.
- test_remember_many: importorskip mcp so the numpy-only core floor skips instead of failing.
- test_bounded_uploads: assert the bounded route class on router.routes — newer FastAPI wraps included routers in one composite object instead of flattening per-path routes onto app.routes; also fix the too-many-fields payload (dict comprehension collapsed 64 fields to one key) and pin the strict 400 contract.
Raw str(ResourceExtractionError) reached import API responses (CodeQL py/stack-trace-exposure, 15 sinks in routes/v2_api.py). Reports now carry canned labels from core.documents._safe_reason; the full message stays in server logs only.

@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: f3b9202135

ℹ️ 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 engraphis/core/engine.py
Comment thread engraphis/core/engine.py
Comment thread scripts/sync.py Outdated
The dependency-free indexer only produced 'defines' edges, so on the numpy-only floor (no tree-sitter) the code-arm bridge could not hop a caller to its callee and code-arm recall collapsed to 0.0 (core-floor CI). The fallback now emits caller→callee 'calls' edges for references to same-file symbols inside detected function bodies — bounded to indexed symbol names, one edge per pair, best-effort by design; the AST backend stays authoritative where a grammar exists.

@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: 99759197d7

ℹ️ 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 scripts/sync.py
Comment thread engraphis/mcp_server.py
Comment thread scripts/cli.py Outdated
- Filter batch sibling context passed to resolution by matching memory type, mirroring _resolve_against_neighbors' own candidate visibility and scoring's per-type weights: a cross-type restatement can no longer drive ADD/NOOP/INVALIDATE.
- Derive per-fact trusted_write from the normalized provenance envelope (prompt_eligible) exactly like the single-write path: untrusted batches (api/web/import ingress) stay passive pending evidence instead of resolving against live memory or minting trusted hints.
- Queue post-commit vector publications only for ops that inserted a record (add/invalidate/relate); noop results reference the pre-existing memory id and must never republish a candidate vector over it.
- Revalidate session liveness inside the batch transaction via store.begin_session_write under the write lock, so a session ended between pre-checks and commit rejects cleanly instead of attaching writes.
_recover_stale_import_jobs borrowed the graph-index 60s lease, so any single document taking longer than a minute (large PDF, OCR image, transcription) got killed by its own status poll mid-file. Imports now carry IMPORT_JOB_LEASE_SECONDS=900 while keeping the existing progress-aware expiry: the per-document heartbeat resets lease age, live workers are never failed, dead workers still expire with worker_lease_expired.
… status

- _consolidation_evidence now appends non-record endpoints of consolidates/profiles links through the visible-append gate, so legacy/repaired digests carrying sources only in the link tables still yield complete grounding evidence.
- scripts.sync --status --repo <name> scopes memory/tombstone counts to the requested repository (_scoped_counts); absent repos report an empty scope instead of workspace totals; no-repo invocations keep workspace-wide totals.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

…hema, error routing

- sync --status --repo: a repository absent from the workspace now reports an explicitly empty scope ('repo: <name> (not found locally)', zero counts) and no longer presents the workspace checkpoint as the requested scope's cursor.
- mcp_server: the remember_many per-fact schema documents evidence_source and states the link predicate (subject_key or evidence_source) matching the engine, so schema-driven agents actually get wired siblings.
- cli: only MemoryService construction maps through _startup_error via a dedicated _ServiceStartupError marker; command-phase OSError/RuntimeError/etc. report honestly as command failures with a value-free strerror instead of advising engraphis-init --check for a directory argument.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@Coding-Dev-Tools
Coding-Dev-Tools merged commit db1a8de into main Aug 23, 2026
23 checks passed
Coding-Dev-Tools added a commit that referenced this pull request Aug 25, 2026
The release workflow's ENGRAPHIS_INDEX_ROOTS omitted tempfile.gettempdir(),
which ci.yml has included since #159. Two suites seed fixtures under the
system temp dir and call index_repo against them:
- eval/code_arm.py (via test_eval_code_arm.py)
- tests/test_documents.py XML/container attack fixtures

Both failed on every Python leg of the v1.6 release run (run 32852978103),
blocking the PyPI publish. Same root cause silently blocked the Aug 15
v1.7/v1.6.1 tag runs. Ported the third approved root to all five pytest
invocations that run the full suite or fixture-dependent modules; the
encryption job keeps the narrower two-root set, matching ci.yml.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@Coding-Dev-Tools
Coding-Dev-Tools deleted the release/v1.6-hardening branch August 25, 2026 16:32
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