release: conexus 7.36.0 - #1515
Merged
Merged
Conversation
…xus-cbo4a) Batch 9 item 1, Sam's directive nexus-zrcj7 (2026-09-05): no session or role search_path reliance, ever. Deletes the remaining 24 per-class "ALTER ROLE ... SET search_path" literals plus db.changelog-test-role.xml's own line -- the role-level half batch 9 item 0 deferred. Nothing replaces them: PgContainerHelper.bootstrapServiceRole and the test-role changelog now set no search_path at all, since every legitimate query already goes through schema-qualified jOOQ generated Tables/Routines or a function-pinned SET search_path in the function definition itself. RawSqlGateTest.scanSessionSearchPathReliance gains a third branch that fails loud on the ALTER ROLE shape (exempting only SharedClusterMutationFalsifyTest's yhmav_poison_schema falsification value, matched on the captured target schema rather than file name), the old negative fixture becomes a positive detection proof, and a resource-scan test asserts db.changelog-test-role.xml can never regain the line. Kept raw with reason, untouched here: SharedClusterMutationFalsifyTest's poison-value ALTER ROLE (nexus-tyiht, a deliberate falsification proof that SharedCluster's reset-at-acquire clears a cluster-wide role GUC).
…per (nexus-cbo4a) Batch 9 item 1, second half. Folds ~27 files' hand-rolled "INSERT INTO nexus.service_tokens ..." sites (prepareStatement, createStatement().execute, and the local wrapper methods several files built around one) onto PgContainerHelper.seedServiceToken: the existing 4-arg overload for a plain token/tenant/label seed, and a new 7-arg overload (scope/expiresAt/revokedAt, each omitted from the INSERT -- never set to a literal SQL NULL -- when the argument is null) for sites that need those columns. ServiceTokenScopeBackfillTest, ServiceTokenSchemaLiquibaseTest, and ReferenceOnlyChunkUpsertTest insert LITERAL (fake) hashes to assert on later, not a real token's sha256, so they convert onto the typed jOOQ SERVICE_TOKENS DSL directly instead -- seedServiceToken always hashes its token argument, which does not fit. ServiceIntegrationTest's hand-built spike schema (its own differently-shaped service_tokens table, documented since batch 7) is left untouched. Re-censused against the real gate (RawSqlGateTest. noRawExecuteSqlRegressionInTestSources's own STALE CEILING failure output, ground truth from scan() itself, not a standalone estimate): combined with the search_path deletion in the prior commit, 36 files changed, -59 sites; TEST_TREE_RAW_SQL_TOTAL_CEILING 1661 -> 1602. Twelve files reached zero and their TEST_TREE_RAW_SQL_CEILING entries are removed outright (145 -> 133 files).
…hape asserts (nexus-cbo4a)
Real production finding surfaced by the search_path deletion (Sam's
directive, nexus-zrcj7): CatalogRepository.deferManifestChunkFk ran
"SET CONSTRAINTS fk_catalog_chunks_chunk DEFERRED" with an UNQUALIFIED
constraint name, which PostgreSQL resolves through search_path. With no
role-level search_path left, it failed "constraint ... does not exist" --
exactly the class of reliance the deletion was meant to surface. Full
Java suite caught it via CatalogDeleteCollectionCascadeTest,
CatalogHandlerDeleteTest, ManifestChunkFkTest,
RdrO8dil7GlobalManifestAntiJoinTest, and StagingPromoteOpsIntegrationTest.
Fixed by schema-qualifying the constraint name; RawSqlGateTest's
SANCTIONED_STATEMENTS entry for deferManifestChunkFk is updated to match.
Same suite run also failed PgVectorRepositoryRawSqlPlanShapeTest's two
bare "<=>" EXPLAIN-text assertions: the vector extension's earlier
relocation into schema nexus (search-path-001/002) means the operator no
longer resolves off search_path, so PostgreSQL now renders the qualified
"OPERATOR(nexus.<=>)" form once no search_path names it. Widened both
assertions to accept either form via a regex on the column projection,
without weakening the dim-column check the assertions exist for.
CombinedQueryParityIntegrationTest.
metadataScoped_excludesTombstonedDoc_evenWhenTopRanked's own precondition
("the tombstoned chunk is a top vector match for its own text") also
failed under -Dgroups=integration, but isolated via a revert-and-rerun of
that file alone: the ORIGINAL (pre-deletion) file fails identically, so
this is pre-existing and unrelated -- filed as nexus-5umlb rather than
fixed here.
…ng; retire stale search_path comments (nexus-cbo4a) Review fold-in for batch 9 item 1 (T2 [24826] items 1-3, [24827] Significant #1). The scan's ALTER ROLE branch is now case-insensitive, accepts "=" as well as "TO", and tolerates a quoted target identifier, with a fixture covering the three variants. CollectionRegistryFkTest, CatalogRepositoryTest and SharedCluster's javadoc no longer claim that bootstrapServiceRole or production set a search_path.
active_installs_28d read 2 within an hour of the v0.1.107 deploy: this box plus a release-battery rehearsal install. NX_NO_TELEMETRY=1 now sits in every env -i allowlist under tests/e2e, is exported by the five non-scrubbing sandbox scripts, and is forwarded by -e into the migration-rehearsal container. tests/test_e2e_no_telemetry_lint.py pins all three.
…documented cost (nexus-atylb) Sam's ruling 2026-09-07: the tail-ranking swap a split embedding-model group shows against the pre-batching fan-out is an accepted cost of batching, to be revisited later. _desired_candidate_count's docstring records the acceptance and the live measurement (rdr, 9 collections, Jaccard 0.667, four ids at ranks 7-10 within 0.005). The parity test derives each corpus's floor from search_engine's own split decision (0.6 when the group splits, 0.9 otherwise) and keeps the strict floor in aggregate as a mean over all queries, so one tail swap passes while a broad drift still fails. Live run 2026-09-07: nine queries at 1.000, rdr at 0.667, mean 0.967, passed.
…wag) RDR-143's SessionStart hook drives wheel + data from a plugin update; this is the reverse, so `nx upgrade` is one verb for all three. After the ladder it reads installed_plugins.json (the one reader, shared with health's orchestration-floor check) and, for each conexus/sn plugin strictly behind the wheel, runs `claude plugin update <id> -s <scope> -y` with stdin closed and a 45 s budget (two fit inside the RDR-143 action's 120 s). One "Plugin update:" line per plugin, silent in lockstep, never fails the upgrade; an exit 0 the parser cannot read is reported as not confirmed. Skipped under --auto, reported under --dry-run. Isolation: NX_PLUGIN_REGISTRY is the registry seam; conftest parks it so no unit test, subprocess included, can run the real claude. 24 unit tests drive a fake claude. tests/e2e/plugin-lockstep-gate.sh drives the REAL claude CLI in a scrubbed HOME (marketplace at the previous tag, install, advance, nx upgrade, registry asserted, real registry mtime unchanged) and then runs the newest plugin's lockstep hook against the previous published CLI in a bare venv; wired as a release-battery leg. Review fold: critique [24831], code review [24832].
Sam's 2026-09-07 ruling on nexus-dkymw (RDR-106 Option A regression): tombstones are the recovery story, not resurrected backup-before-delete machinery. nexus.document_restore (catalog-003-soft-delete.xml, RDR-156 P1.2) has existed since that changeset with no caller anywhere in the stack; nexus-xavu7 found three operator-facing sites telling an operator to "restore the trashed document(s)" with no surface to do it. - CatalogRepository: restoreDocument(tenant, tumbler) mirrors deleteDocument's direct-jOOQ-DSL tombstone writer, guarded by DELETED_AT.isNotNull() (idempotent restore); listTrash(tenant, limit, offset) is the read-only counterpart. - CatalogHandler: POST /v1/catalog/restore, GET /v1/catalog/trash. - TombstoneFilterGateTest: both methods registered as named TOMBSTONE_EXEMPT entries (restoreDocument is the second sanctioned un-tombstone alongside upsertDocument's ON CONFLICT arm; listTrash mirrors agedTombstoneCount's rationale); floor_setDeletedAtSites 3->4. - CatalogHandlerEnvelopeConformanceGateTest: both routes classified (neither for /restore's scalar response, collectionOk for /trash's documents/count envelope). - New CatalogRestoreTrashTest: restore flips a tombstone and the doc reappears in list/show; restore of a live/unknown tumbler is a no-op; manifest and chunks survive a tombstone+restore round trip; restore after purge-trash has reclaimed the row returns 0; trash lists only the calling tenant's tombstones and excludes live documents. Full service suite: 2635 tests, 1 pre-fix failure (the conformance gate above, fixed), 0 after. Scoped rerun (CatalogRestoreTrashTest, CatalogHandlerEnvelopeConformanceGateTest, RawSqlGateTest, TombstoneFilterGateTest): 88/88 green.
Client half of nexus-dkymw, the engine routes' first caller. Closes nexus-xavu7 (three sites told an operator to "restore the trashed document(s)" with no surface to do it) by naming the new verbs at every one of those sites and removing every remaining "manual restore" / hand-written-SQL claim. - HttpCatalogClient.restore_document/list_trash: thin wire wrappers over POST /v1/catalog/restore / GET /v1/catalog/trash. 404 propagates raw (same discipline as purge_trash) for the CLI to turn into a clear engine-floor error. - factory.py: restore_document joins _SERVICE_ONLY_WRITE_OPS (same disposition as purge_trash/delete_many/delete_collection -- a service-only op with no local-catalog equivalent, so it is deliberately NOT added to the shared CATALOG_WRITE_OPS/ catalog_protocol.py Protocol pair, which requires a matching canonical Catalog method for test_catalog_protocol_fidelity.py's shape check). list_trash is a read and needs no whitelist entry. - New src/nexus/commands/catalog_cmds/trash.py: `nx catalog trash` (list tombstones) and `nx catalog restore TUMBLER_OR_TITLE` (title resolution falls back to the trash listing when the live resolver misses, since live reads hide tombstoned rows by design). - Updated the three nexus-xavu7 guidance sites (collection_rename.py, catalog_cmds/collections.py's rename-collection, catalog_cmds/ doctor.py's --collections-drift) plus the delete verb's own docstring/echo, purge_trash's client/CLI docstrings, store_hook.py, db/collection_state.py, docs/operations/t3-health.md, and docs/cli-reference.md (new "nx catalog trash / restore" section) to name `nx catalog restore` instead of a nonexistent manual-restore path or hand-written SQL UPDATE. - tests/catalog/test_http_catalog_client.py: FakeCatalogHandler gained /restore and /trash branches (test_fake_catalog_handler_route_census requires every real route to be faked or excluded). - New tests/test_catalog_trash_restore.py: HttpCatalogClient wire contract, _ServiceCatalogWriter admission, and CLI coverage (success, no-op, title-fallback-to-trash, ambiguous title, unknown, engine-floor 404) for both verbs. restore_many was left out (delete_many's positional-vs-membership-set return shape isn't a trivial mirror, and nothing client-side needs it yet). tests/test_catalog_trash_restore.py + tests/test_catalog_purge_trash.py + tests/catalog: 429 passed. ruff check on all touched files: clean.
…tle collision Two review fold-ins for nexus-dkymw (T2 [24833], [24834]), client tree only. CRITICAL (docs overclaim, T2 [24834]): every site claiming a tombstoned document's row/manifest/chunks "stay together for the whole purge-trash window" and that restore "works throughout" was true only for nx catalog delete / nx catalog purge-trash. Qualified docs/cli-reference.md (both mentions), the trash.py module/verb docstrings, http_catalog_client.py's restore_document/purge_trash docstrings, store_hook.py's store_delete_catalog_cleanup docstring (which was stating the GENERIC delete_document contract about its OWN tombstone, even though that tombstone runs after the MCP store_delete tool has already hard-deleted the T3 chunk in the same call -- restoring the row there can never bring the content back), and docs/operations/t3-health.md's collections-drift guidance -- each now names the three verbs whose chunk/row loss nx catalog restore cannot undo: nx t3 gc (chunk-indexed_at-clocked orphan sweep, independent of purge-trash's window, alive-set excludes tombstones immediately -- can reap a just-tombstoned document's chunks INSIDE the grace window), the MCP store_delete tool (tombstones the row and hard-deletes the T3 chunk in the SAME call -- no window at all), and nx collection delete / nx collection prune (purge_collection_cascade -- irreversible, never tombstones). Behavior of those three verbs is unchanged; this is documentation only. IMPORTANT (title-collision bug, T2 [24833]): _resolve_restore_target tried the live resolver first, so a title present both live and in the trash resolved to the live doc and reported "already live" with no mention of the restorable tombstoned copy. Rewrote it to check the live resolver AND the trash listing together: a title matching both is now refused as ambiguous, naming every tombstoned tumbler and telling the operator to pass a tumbler; a title matching only the live doc still no-ops on "already live" but now says explicitly that nothing under that title is in the trash. tests/test_catalog_trash_restore.py: two new tests (live+trash collision refuses ambiguous; live-only match's refined no-op message). tests/test_catalog_trash_restore.py + tests/catalog: 397 passed. ruff check on all touched files: clean.
…declaration lint (nexus-atylb)
…sandbox opt-out lines (nexus-tb01a)
…ngine) Sam's second 2026-09-07 ruling on nexus-dkymw: chashesForCollection (the nx t3 gc / indexer-prune alive-set) must keep a tombstoned-but-not-yet- purged document's chashes alive until nexus.purge_trash physically reclaims the row, superseding nexus-mqd6t's original DELETED_AT.isNull() filter for this one read. Without this, t3 gc's own --orphan-window clock (independent of purge-trash's window) could reap a just-tombstoned document's chunks inside nx catalog restore's recovery window, so restore resurrected an empty shell. Read-invisibility of tombstoned content elsewhere (search results, getManifest) is unchanged. - CatalogRepository.chashesForCollection: drop the DELETED_AT.isNull() filter; document both rulings inline. - TombstoneFilterGateTest: register chashesForCollection as a named TOMBSTONE_EXEMPT entry citing the supersession. - CatalogEngineDefects70Test: flip mqd6t's BUG 1 test to the new contract (tombstone keeps the chash alive; purge_trash removes it). - CatalogRestoreTrashTest: add a round-trip test asserting the alive-set protects the chunk through a full tombstone -> restore cycle. Scoped: CatalogEngineDefects70Test + CatalogRestoreTrashTest + TombstoneFilterGateTest + RawSqlGateTest, 144/144 passed. Full suite: 2636 run / 0 failures / 0 errors / 7 skipped.
…lient) Client half of the engine's chashesForCollection alive-set fix (nexus-dkymw, Sam's second 2026-09-07 ruling): update every carve-out site that told operators nx t3 gc's orphan sweep could reap a just-tombstoned document's chunks inside nx catalog restore's recovery window. That is no longer true -- the alive-set now protects a tombstoned-but-not-yet-purged document's chashes, so only the MCP store_delete tool and nx collection delete/prune still bypass the restore window. - HttpCatalogClient.purge_trash/restore_document docstrings: narrow the carve-out from three paths to two. - commands/catalog_cmds/trash.py: module docstring and both verb docstrings updated the same way. - commands/t3.py: gc_cmd help text gains a TOMBSTONE PROTECTION section; the chashes_for_collection call site's comment documents the ruling. - indexer.py's _prune_deleted_files alive-set-read comment updated. - indexer_utils.py's non_complete_documents docstring: "every live document's manifest" corrected to include still-tombstoned documents. - docs/cli-reference.md (nx catalog trash/restore section and the purge-trash age-semantics paragraph) and docs/operations/t3-health.md (collections-drift guidance): same narrowing. - tests/db/test_i711w_gap_xfails.py and tests/test_catalog_manifest_read_api.py: flip the two mqd6t pins to assert protection instead of exclusion, with two-ruling docstrings. The physical-reclaim half is pinned at the engine layer only, since the wire-level purge-trash endpoint refuses older_than_days < 1 and neither fixture has a deleted_at-backdating helper. Scoped: tests/test_t3_gc.py tests/test_catalog_manifest_read_api.py tests/db/test_i711w_gap_xfails.py tests/test_catalog_trash_restore.py tests/test_indexer.py -- 198 passed, 14 deselected, 2 xfailed. ruff check on all touched files: clean (same 30 pre-existing PLC0415 findings as the unmodified tree, zero new).
… (engine) Review fold-in (T2 [24838]/[24839], both clean of blockers): the rationale in the prior commit claiming this fix protects the indexer's orphan-quarantine prune was stale. Traced _prune_deleted_files: its delete decision runs through the engine SQL function nexus.gc_quarantine_orphans (catalog-023 / vectors-005), whose anti-join checks catalog_document_chunks row existence only and never joined deleted_at; the client-side fallback that once consulted chashes_for_collection for orphan classification there was retired at RDR-191 Phase 6 (2026-08-15, nexus-o8dil.33). chashes_for_collection is used in that path only as an empty-manifest skip guard. Reworded, no code changes: - CatalogRepository.chashesForCollection javadoc: states the genuinely fixed caller is the nx t3 gc CLI verb (which diffs T3 chunks against this exact returned set); the indexer's own prune was already tombstone-tolerant by construction and was never at risk. - TombstoneFilterGateTest's chashesForCollection TOMBSTONE_EXEMPT rationale: same correction. Scoped: TombstoneFilterGateTest + RawSqlGateTest, 72/72 passed (19+53, 0 failures, 0 errors).
… (client) Client half of the engine fold-in: the indexer's orphan-quarantine prune (_prune_deleted_files) was never at risk from nexus-mqd6t's original exclusion filter and gains nothing from this fix -- its delete decision runs through the server-side anti-join nexus.gc_quarantine_orphans, which checks manifest row existence only and never joined deleted_at, so it was already tombstone-tolerant by construction. The client-side fallback that once used chashes_for_collection for orphan classification there was retired at RDR-191 Phase 6 (2026-08-15); today it is called only as an empty-manifest skip guard. - indexer.py's _prune_deleted_files comment: reworded to state the above instead of implying this prune needed protecting from a restore-window reap. - indexer_utils.py's non_complete_documents docstring: clarified the alive-set description is specific to nx t3 gc's own manifest-vs-T3 diff, distinct from the indexer's server-side-anti-join prune. - docs/operations/t3-health.md: softened "now respects that same window too" to "protected until purge-trash reclaims the row", matching the wording used elsewhere in this diff. ruff check src/nexus/indexer.py src/nexus/indexer_utils.py: clean.
…ionTxn's, not deleteCollectionTxn's; chunks_collection_fk cited from fk-004; quarantine backfill and zero-blank cases added to Phase 1 and the Test Plan; redundant catalog_documents clause dropped; bead, changeset and jargon glossed on first use
… from catalog-001-5, not fk-002; collectionIsEmpty answers, it does not refuse (three sites); Phase 1 item 1 drops the separate physical_collection check; Finalization Gate reads the six passes and the five verified assumptions; three bead ids glossed
…ence, no invented entry numbers
…4 in related_rdrs; eight critiques counted; model_version's fate stated (client-supplied, never parsed, untouched by the walk); legacy_grandfathered and catalog_meta glossed at first use
…al Assumption 4 states the two-tenant segment census as measured (nexus 106 two-segment rows, none with chunks; gate-xr789 none), research-13 cited
… 204-research-14: legacy_grandfathered is RDR-101 Phase 6's flag; model_version is the name's v<n> parsed once at registration and retired with the other parses; the third two-segment citation names research-13; assumption 3 names the version segment
… registration sites, enumerated in 204-research-15; the universal 'only' is gone from assumption 3, the walk paragraph and Phase 1 item 4
…n bullet names the five parse sites, the hardcode's current line (index.py:110), and that Phase 1 replaces the model while the name parse goes with Phase 3 (204-research-16)
…match the artifact's text (nexus-g7zgw.3) Two legs the reference-rot lint lacked, both taken from RDR-204's gate loop: a changeset-shaped token whose family exists in the Liquibase changelog must name a file stem, a changeSet id or the bare family; and an attribution of a backticked identifier to a changeset or an RDR (created, added, defined, dropped, owns, or the trailing 'RDR-NNN set' form) requires the identifier to occur in that artifact's own text. Existing misses are allowlisted by value with reasons; planted tests keep each leg non-vacuous.
…earch-4 for assumption 3 (fix-check [24860] observation)
…ck, round-capped aggregation, fix-commit rule (nexus-g7zgw.1 .2 .4 .5)
The re-gate block of `nx rdr preamble rdr-gate` now prints whenever a gate
record exists, PASSED or BLOCKED (both RDR-204 rounds that introduced new
Criticals followed a PASSED gate, with the sweep structurally off), carries
the gate round derived from the record's prior chain, and prints a Fix check
section naming the exact diff range, the fix commits and the T2 title
`{id}-fix-check-<tip sha>` whenever the RDR changed since the gated commit.
Skills and command: Layer 0 sweeps the critic's per-finding Sites list; the
Fix check layer verifies only the diff (contradiction within the file,
attribution/count/universal without enumeration, cited source lacking the
claim) before Layer 1; Gate Aggregation blocks on any Critical in rounds 1
and 2 and on ship_blockers only from round 3, recording the rest as
residuals the accept skill dispositions; Criterion 6 never yields a finding;
a fix changes the named fact and nothing else, with the research entry
written before the edit (rdr-research § Pre-edit capture).
Design of record: T2 nexus/deep-analysis-rdr-gate-fix-loop-2026-09-07.
The re-gate block flags a gate record whose fix_check sha differs from its commit (the invariant was prose-only and the live RDR-204 record already violated it); the accept skill blocks on the same mismatch. The critique extractor carries the critic's Sites line into the printed block, the printed Layer 0 text sweeps that list first, and substantive-critic.md's canonical Issue format gains the Sites line. A failed git log in the fix check names the failure instead of printing HEAD as the tip sha. The attribution lint matches identifiers on word boundaries. Skill, command and preamble wording aligned (round formula, Layer 1 or Layer 3, the research-entry clause of the enumeration rule, conservative default when a Verdict omits ship_blockers).
…he T2 critique prefix instead of carrying a count
… one shape for formula_content_detected (nexus-5yrob, nexus-aabdr) An empty process_command read is a ps timeout as often as a vanished process, and deleting the pid file on it would orphan a server that is still ours; the stop verb now signals nothing and says so, and only a live command that classifies as something else removes the file. The Docling-path formula_content_detected event carries source="docling" so both emitters of the event share one field shape.
…ache (nexus-g6xpa) The service build lease moves from <checkout>/service/.build-lease to <git common dir>/nexus-build-lease, so every worktree of the repo shares it; measured 2026-09-07, three worktree agents ran three full engine suites at once (twelve surefire JVMs) because each had its own lease. mvnw-leased.sh, build-gate-jar.sh and build-artifacts.sh now wait for a live holder (build_lease_acquire_wait, NX_BUILD_LEASE_WAIT, default 3600 s; 0 refuses as before). A pid-less lease directory younger than 10 s counts as held, so a poller can no longer reclaim a lease mid-populate. tests/db/_service_fixture.py resolves the same root, pinned by a parity test from both sides. build-gate-jar.sh caches the stamped jar in the common dir keyed on the exact service/ working-tree content (throwaway git index, stamp lines normalized out), the release_version and the mvn args; a hit copies the jar and reprints its build_ref, a miss builds and publishes by rename. A fresh worktree with an unchanged tree no longer pays the nine-minute rebuild. build-gate-jar_test.sh drives the miss, hit, polluted-stamp and failure-restore paths against a stub mvnw. bare_mvnw_lint_test.sh also gains build-artifacts.sh as self-guarded; it acquires the lease at its top and had been red since it landed. Reviews: T2 nexus/code-review-nexus-g6xpa-lease-and-gate-jar-cache [24921], nexus/critique-nexus-g6xpa-lease-and-gate-jar-cache [24922].
…does not know instead of reporting full coverage (nexus-ngpx0) A bare subject name returned zero catalog entries, so zero gaps, so the clean-coverage message for a collection where 54 of 58 rows had no aspect record. Zero rows is a refusal that names the physical collection name as the remedy, never a pass.
…yped jOOQ DSL nexus-cbo4a batch 12: 39 -> 16 sites. Seed inserts onto HEAD-schema generated jOOQ tables (catalog_documents/catalog_links/catalog_collections/hook_failures/ document_aspects/aspect_promotion_log/plans/topics/topic_links). databasechangelog reads (Liquibase's own bookkeeping table, no jOOQ codegen) onto the schema-agnostic DSL.table(DSL.name(...))/DSL.field(DSL.name(...), Class) form. The jsonb/timestamptz cast oracles onto typed DSL.cast chains. One DROP VIEW onto DSLContext#dropView. The five mid-rollback column-probe wrappers (queryOneNullableString/queryOneInt/ queryOneNullableBoolean/assertNullColumn/assertTimestampEquals) onto a shared fetchColumn helper typed dynamically per call site, since the column's actual Postgres type varies by rollback depth (TEXT/INTEGER post-rollback, TIMESTAMPTZ/ JSONB/BOOLEAN post-reapply) -- a fixed generated-table Field would be wrong at half this file's call sites, so the schema-agnostic form is mandatory here too. Kept raw with reasons documented inline: bootstrapVectorExtensionsForFreshWalk's 9-site DBA bootstrap (CREATE EXTENSION/CREATE SCHEMA AUTHORIZATION/CREATE FUNCTION, no jOOQ typed form for any shape, same class as SchemaMigratorIntegrationTest's own kept-raw admin bootstrap), the CREATE ROLE nexus_diag BYPASSRLS bootstrap, one execute(sql) replaying grants-nexus-diag-1's own changeset body verbatim, and dbaBootstrap's 5-site admin/svc role bootstrap against a dedicated container. Verified: scoped mvnw-leased.sh test -Dtest=SchemaRollbackRoundTripIntegrationTest, RawSqlGateTest -- 4 + 53 = 57 tests, 0 failures, BUILD SUCCESS.
… DSL
nexus-cbo4a batch 12: 81 -> 50 sites. databasechangelog reads onto the
schema-agnostic DSL.table(DSL.name("databasechangelog"))/DSL.field(DSL.name(...),
Class) form. nexus.memory INSERT/SELECT onto the generated MEMORY table. The
mid-ladder DROP CONSTRAINT/[NO] FORCE ROW LEVEL SECURITY/ADD CONSTRAINT NOT
VALID/VALIDATE CONSTRAINT sites onto PgContainerHelper's typed DDL helpers
against either a generated table or, for chunks_384/chash_index (dropped at
HEAD), DSL.table(DSL.name("nexus", "<table>")). Seed INSERTs onto generated
jOOQ tables (CATALOG_DOCUMENTS/CATALOG_DOCUMENT_CHUNKS/CHUNKS/
CATALOG_COLLECTIONS).
New PgContainerHelper.installTestObjects(Connection), hoisted out of
applyProductSchema: this file's dedicated-container aged-box tests never call
applyProductSchema, so the typed DDL helpers' nexus_test.* backing functions
were missing on those containers. Installed via the MIGRATING role's own
connection rather than su, since whichever Liquibase run creates
databasechangelog first owns it -- installing via su would leave it
superuser-owned and the migrating role's own product-changelog walk would
then hit "permission denied for table databasechangelog".
VALIDATE CONSTRAINT conversions switch their expected exception from
PSQLException to org.jooq.exception.DataAccessException (a jOOQ Routine call
wraps the underlying PSQLException), matching batch 10's own precedent.
Kept raw with reasons documented inline: bootstrapVectorExtensionsForFreshWalk's
9-site DBA bootstrap, 8 occurrences of a 5-site admin/svc role bootstrap
against a dedicated container (bootstrap() plus 7 aged-box tests), and one
chunks seed INSERT whose bare, deliberately unqualified ::vector cast is the
test's own subject (VectorBinding always renders ::nexus.vector, which would
change what that statement proves).
Verified: scoped mvnw-leased.sh test -Dtest=SchemaMigratorIntegrationTest,
RawSqlGateTest -- 16 + 69(incl. overlap) tests, 0 failures, BUILD SUCCESS.
…helper itself (nexus-cbo4a, critique [24929])
… pins hold (nexus-cbo4a)
…ubstitution, not a pipe into grep -q (nexus-g6xpa)
…(arXiv:2608.20845) Replicates the paper's compiled-payload experiment in nexus's own consumer shape: same reader, prompt and retrieval, payload either the retrieved chunks or the retrieved documents' aspect rows. On 40 questions over knowledge__dt-papers the aspects payload scored 27.5% and 32.5% at 2k and 8k token budgets against 75.0% and 85.0% for chunks, with paired wins of 21 to 2 and 22 to 1. Document-level paraphrase aspects are not a retrieval payload; the atomic claims layer stays unbuilt. Record: T3 catalog 1.11.533, T2 nexus/isc-payload-ab-result-2026-09-07.
…wg3) CatalogRepository.tombstoneProtectedChunkCount(tenant, collection) reuses strandedChunkCount's own anti-join -- the same predicate nexus.purge_trash's chunk sweep uses, tenant-wide and collection-blind on the manifest side -- at olderThanDays=0, so hasProtectingManifest collapses to "referenced by a live document" only. strandedChunkCount gained a collection-scoping overload; the filter is output-side only, so a chash tombstoned in one collection but live-referenced from a document in another collection is still correctly excluded (matching what purge_trash will actually do). GET /v1/catalog/manifest/chashes gains tombstone_protected_count in its existing envelope (additive; old clients ignore the unknown key). Redo of the client-side cut in critique T2 nexus/critique-nexus-zewg3, which re-implemented a predicate the engine owns and could disagree with purge_trash on cross-collection chashes.
…n the catalog row, /conexus:devonthink-index (nexus-i0cwh) `nx dt index` reads each record's properties over the DEVONthink MCP once per run and, on a fresh PDF index, compares the pages the extractor produced text for with DEVONthink's pageCount. A gap is a per-record failure naming the missing pages and a non-zero exit; --allow-page-gap accepts it; an unreachable MCP or an extraction with no per-page text is reported as unverified, never as covered. The gap is recorded as meta.page_gap on the catalog row and cleared on the next full-coverage run. The same read stamps year (when the PDF carried none), meta.devonthink_url and meta.devonthink_page_count beside the x-devonthink-item identity. The coverage oracle is the extractor's own per-page callback: PDFExtractor.extract now records pages_with_text in its result metadata, the streaming pipeline and the batch chunker hand it to index_pdf, and index_pdf's return_metadata carries page_count and pages_with_text. Chunk page numbers only mark where chunks start; a 20-page slide deck in seven chunks read as thirteen missing pages under that oracle, measured live. Stage 1 of the route is /conexus:devonthink-index, a thin command over the verb via nx command-context devonthink-index (selector to invocation, MCP reachability, knowledge subjects, the coverage rule). The native verb already existed (RDR-099 P2, RDR-139); the bead's copy- to-durable-dir step is dropped by Sam's ruling: read in place, identity on the URI.
…s (nexus-zewg3) The count is computed only when the request carries with_tombstone_protected=1, so the indexer's per-collection alive-set call on every nx index repo run pays nothing for a field it never reads (critique T2 nexus/critique-nexus-zewg3-engine-side Significant 1). Envelope test covers both forms.
…zewg3) nx t3 gc now reads tombstone_protected_count from the same round trip that returns the alive-set (HttpCatalogClient. chashes_for_collection_with_tombstone_protected wraps GET /manifest/chashes's additive field), rather than re-deriving it client-side. Both dry-run and --no-dry-run --yes runs print "Protected by pending tombstones: N chunk(s) (reclaimed by 'nx catalog purge-trash' once past its --older-than-days window, never by t3 gc)", naming nx catalog purge-trash as the verb that reclaims that class. An engine that predates the field reports the line as "unavailable on this engine" rather than a confident zero; the gc_audit details and the structured t3_gc_chunks_deleted log event carry the same value (null when unavailable, never 0). Redo of the client-side derivation in e19ac828f (not landed): that version paged GET /v1/catalog/trash tenant-wide and diffed against a full-collection get_manifests call, which could disagree with what purge_trash actually reclaims on a cross-collection chash and cost a second round trip per run. The engine-side count (prior commit) closes both gaps.
…re-shape test and ledger entry (nexus-zewg3) chashes_for_collection_with_tombstone_protected passes with_tombstone_protected=1; chashes_for_collection does not. The method body now has its own test through the real _get boundary (present -> int, absent -> None, count reconciliation kept). docs/wire-contract-pending.md gains the [additive] entry for the split pairing.
…ft fixes CHANGELOG.md: new 7.36.0 section covering nx catalog trash/restore and the t3 gc tombstone-protection fix (nexus-dkymw, nexus-xavu7), the retirement of nx catalog setup from every remedy (nexus-owna8), MinerU pid/stop hardening (nexus-5yrob, nexus-aabdr, nexus-ajfld, nexus-8sb6x, nexus-ho9d2, nexus-ydqwo), the PDF auto-mode Docling skip (nexus-m5ym5), the aspects-list --missing refusal (nexus-ngpx0), the index write-model fix (nexus-ft04v.34), the RDR gate-loop/rdr-fix surface (nexus-zbdm0, nexus-g7zgw, nexus-dv7gw, nexus-yxo2l), and developer-facing items (the shared engine build lease/gate-jar cache, nexus-g6xpa; the raw-SQL test-tree conversions, nexus-cbo4a; the recall-parity acceptance, nexus-atylb). Pairs with engine-service-v0.1.108 (additive). conexus/CHANGELOG.md: a 7.36.0 section rewriting PENDING_RELEASE.md's Awaiting entries as shipped plugin-surface changes (the ledger itself is untouched; it clears when source.ref actually advances). docs/cli-reference.md: fixed two drift spots found in the audit against this window's commits — nx mineru stop's description was silent about the new process-group signal, pid-recycle refusal, and inconclusive-read no-op (nexus-5yrob/aabdr/ajfld/8sb6x); nx enrich aspects-list --missing didn't mention the new refusal for a collection the catalog does not know (nexus-ngpx0). docs/architecture.md and README.md were checked against the same commit range and found clean. tests/fixtures/bead_ids.txt: refreshed via scripts/refresh_bead_id_manifest.py to pick up nexus-5yrob and nexus-ngpx0, both cited in the cli-reference.md fix and both real, already-filed beads the manifest predates.
…ost; both aspect verbs refuse an unknown collection (nexus-oc98c, nexus-3ygp3) The scholarly-paper-v1 extractor stamped rows claude-haiku-4-5 while its subprocess ran on the ambient CLI default (claude-fable-5 on the measuring box, about ten times the cost). The config's model_version is now passed as --model, and each extraction logs the envelope's total_cost_usd, models and duration as aspect_extractor_usage, which the extractor used to discard. Measured 2026-09-07 on haiku with real papers: $0.13 to $0.31 per paper against the $1.18 dry-run constant. nx enrich aspects shared the vacuous shape db86de5 closed for aspects-list --missing: a bare collection name the catalog does not know printed "No documents to process" at exit 0. Both verbs now raise the same refusal, and the audit computes the aspect side first so orphan rows are still reported. Tests were green on the extractor and enrich modules before the last two edits; the engine test substrate is refused while the release battery holds the service build lease, so the final run is pending.
… nx dt index page coverage
…al case names no cloud token (nexus-ft04v.34) The mode-declarations census (CI job "pytest (mode-declarations census)") failed on 8aaf417: four tests referenced a Voyage token without the cloud_mode fixture. The two cloud cases now use the fixture; the local case asserts the bge prefix instead of naming the token it must not send, so no exclusion entry is needed and the exclusion ratchet holds.
…108) with its provenance (7.36.0)
A pipeline buffer written before pages_with_text existed now reads as unverified, never as a 100% gap: the field stays None end to end when the extraction metadata lacks it. A MinerU batch names every page it covers (page_numbers) so the collector counts the whole batch, not its first page. A DEVONthink record with no usable pageCount is tallied as unverified with its own reason instead of vanishing from the summary. DEVONthink's record name becomes the catalog title beside url and year, which the bead's acceptance names. The failure message names the oracle it uses.
…d pages_with_text (nexus-i0cwh) The fake pipeline reports no extraction stats, so pages_with_text is None (unverified), and the empty-meta shape carries page_count 0 and an empty pages_with_text list.
… on haiku, usage logged before the envelope check, extraction refusal counts orphans (nexus-oc98c, nexus-3ygp3) Review of cc4f234 found two operator-facing strings still claiming the ambient default model as the cost basis and the $1.18 constant still measured on the wrong model. The constant is now the mean of three haiku dispatches through the production prompt over real papers ($0.20), the banner names the configured model, usage is logged before the result-key check so a malformed envelope's spend is still recorded, and the extraction verb's refusal names orphan aspect rows the way the audit does.
…al-mode collection token (nexus-i0cwh) The mode-declarations census reads a cloud embedder token as a cloud_mode claim; the fake collection list now carries the bge token, so no exclusion entry is needed.
…th_text None (nexus-i0cwh) The fake pipeline reports no extraction stats; the dict index_pdf builds on the streaming path carries pages_with_text None (unverified), not an empty list.
…oned document's chunk survives until purge-trash and the verb names it (nexus-dkymw) tests/db/test_i711w_gap_xfails.py's integration-only gc journey still asserted the pre-ruling contract (the tombstoned doc's chunk is an orphan and gets collected); the alive-set change (545ed06) flipped the unit-level pins but this test runs only under the local-service gate, where it went red on the 7.36.0 battery. It now asserts the chunk survives and the report line counts it as tombstone-protected.
…s engine-service-v0.1.108
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release conexus 7.36.0, paired with engine-service-v0.1.108 (additive; deployed and cloud-gated before this tag).
Engine pairing: REQUIRED_ENGINE_VERSION (0,1,108). Engine delta over v0.1.107 is service/src/main only (catalog restore/trash routes, t3 gc alive-set protecting tombstoned documents, opt-in tombstone_protected_count on /manifest/chashes, schema-qualified SET CONSTRAINTS); no Liquibase changesets, no /version fields. v0.1.108 was tagged on fa21c24 after: full Java suite 2659/0/0/7, CANDIDATE SHAKEOUT PASSED, PUBLISHED-CLIENT WRITE GATE PASSED, RDR-194 CC5 gate clear. Post-publish: ACQUIRE GATE PASSED; conexus deploy STEP-6 green (gate-report-20260908T011402Z-v011.json, parity 113/113, recall 12/12, GC leg 9/9); CLOUD CLIENT-PATH GATE PASSED 4/4; deployed-engine-version recorded.
Client: see CHANGELOG.md 7.36.0. Highlights: nx catalog trash / nx catalog restore (nexus-dkymw); t3 gc protects tombstoned documents and reports the tombstone-protected count (nexus-dkymw, nexus-zewg3); nx catalog setup retired from every remedy (nexus-owna8); MinerU pid/stop fixes and PDF auto-mode Docling skip (nexus-5yrob, aabdr, ajfld, 8sb6x, ho9d2, ydqwo, m5ym5); aspects run on the stamped model and refuse unknown collections (nexus-oc98c, 3ygp3, ngpx0); nx dt index page coverage and DEVONthink metadata (nexus-i0cwh); RDR gate loop and rdr-fix surface (nexus-zbdm0, g7zgw, dv7gw, yxo2l); shared engine build lease (nexus-g6xpa); raw-SQL test-tree ratchet 1661 -> 1191 (nexus-cbo4a).
Battery (release worktree, this tree): see the ship record T2 nexus/release-7.36.0-ship-2026-09-07 for the verdict table.