Skip to content

feat: add provenance-bound retrieval reference foundation - #487

Closed
100yenadmin wants to merge 2 commits into
stephenschoettler:mainfrom
100yenadmin:research/stable-retrieval-handles
Closed

100yenadmin wants to merge 2 commits into
stephenschoettler:mainfrom
100yenadmin:research/stable-retrieval-handles

Conversation

@100yenadmin

Copy link
Copy Markdown
Contributor

Summary

  • add named, provenance-checked migrations for a durable database authority UUID and the retrieval_references_v1 server-side registry without incrementing numeric schema version 5;
  • add a strict V1 opaque rh1_ envelope codec plus issue, resolve, revoke, and explicit-clone-rotation primitives that store only SHA-256 token digests;
  • add host-supplied authorization seams with pre-lookup authorization and stored-scope authorization before target/revision disclosure;
  • fail closed on incomplete migration provenance, malformed registry schema/state, database replacement, malformed canonical JSON, non-finite timestamps, revocation, expiry, and unsupported envelopes;
  • document the frozen foundation contract and add deterministic migration, transaction, authorization, disclosure, restore, clone, schema, and codec coverage.

Why

Raw database-local IDs and positional cursors are locators, not durable references. They cannot distinguish an ordinary restart from database replacement, detect target revision drift, or prove that the current trusted host context is authorized for the stored scope.

This PR implements only the additive V1 foundation needed by #476: durable logical-database identity, a digest-only opaque-reference registry, strict serialization and typed failures, and host authorization boundaries. It intentionally does not emit references from public tools, add pagination/adapters, define principal or tenant schemas, or add MAC/signing/key management.

The registry and database UUID are governed by named migration provenance while the existing numeric schema version remains 5. Completed healthy migrations are read-only; incomplete, damaged, or exact-shape-but-unmarked authority state is rejected rather than silently adopted or regenerated.

Validation

  • Focused validation: python -m pytest tests/test_retrieval_reference_contract.py tests/test_retrieval_reference_safety.py tests/test_db_bootstrap_fts.py tests/test_schema_stamp_remediation.py -q -o addopts= -> 93 passed, 4 xfailed
  • Default validation:
    • python -m pytest tests/test_lcm_core.py tests/test_lcm_engine.py tests/test_packaging_install.py tests/test_tool_contracts.py tests/test_lcm_command.py -q -o addopts= -> 1148 passed, 1 skipped
    • pytest -q -> broad run remains red only on four failures independently reproduced on accepted main: two import-externalization assertions and two macOS /var versus /private/var path-alias assertions; no candidate-path regression was found
    • scripts/validate_release.sh --full --keep-going --output /tmp/hermes-lcm-release-validation-retrieval-references-v1 -> not rerun for this additive foundation; stacked prerequisite PR fix: serialize concurrent FTS bootstrap repair #486 completed the release validator, while this exact candidate completed the focused and neighboring matrices above
    • git diff --check upstream/main...HEAD && git diff --check && git diff --cached --check
  • Workflow validation, if workflows changed: actionlint -> not applicable; no workflow files changed
  • Static validation: python -m ruff check db_bootstrap.py retrieval_references.py tests/test_retrieval_reference_contract.py and Python compilation -> passed
  • Fresh ad-hoc verifier -> operation provenance, NULL digest rejection, and DDL-free healthy named-migration behavior passed; temporary source and bytecode were removed
  • Exact-current independent adversarial review -> approved immutable file hashes after reproducing every prior blocking mechanism

Notes

  • This PR is intentionally stacked on fix: serialize concurrent FTS bootstrap repair #486 (f0fd3608) because it extends the same bootstrap surface. Review the retrieval-reference commit bf44dc8 independently; after fix: serialize concurrent FTS bootstrap repair #486 merges, the base range should collapse to this commit.
  • Existing scalar IDs and public tool schemas are unchanged. No reference adapters or public tool emission are included.
  • Authorization context is trusted caller-supplied host context. Token provenance is never treated as caller authentication or authorization.
  • A byte-for-byte restore preserves authority and valid registry entries. Explicit clone rotation requires trusted authorization and revokes existing entries atomically.
  • The preserved characterization file tests/test_retrieval_reference_safety.py remains outside this commit because it predates the implementation candidate.

Refs #476

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

ℹ️ 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 db_bootstrap.py
owner_rebuild_needed = (
_fts_needs_rebuild_structural(conn, spec) if winner_state_needs_repair else False
)
if not owner_rebuild_needed and not structural_repair_needed and deep_repair_needed:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Run the deep FTS check when repairing missing triggers

When an FTS trigger has disappeared and content was subsequently updated without changing the row count, structural_repair_needed is true solely because of the missing trigger while _fts_needs_rebuild_structural remains false. This guard then skips the only deep integrity check, so an explicit doctor repair merely recreates the trigger, clears the corruption marker, and leaves the already-stale index malformed; the deep check must still run for this combination.

Useful? React with 👍 / 👎.

Comment thread retrieval_references.py
Comment on lines +686 to +688
SELECT target_json, revision_json
FROM {RETRIEVAL_REFERENCES_TABLE}
WHERE token_digest = ?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Revalidate lifecycle state after scope authorization

When another connection revokes the reference or rotates the database UUID while authorize_scope is running, the earlier lookup contains the now-stale revoked_at and authority state, while this post-authorization query fetches only the target and revision. Resolution therefore returns the protected binding successfully even though revocation or clone rotation completed before disclosure; perform the reads in one consistent transaction or recheck authority and revocation in this final lookup.

Useful? React with 👍 / 👎.

Comment thread db_bootstrap.py
Comment on lines +782 to +785
actual_columns = [
str(item[2])
for item in conn.execute(f"PRAGMA index_info({index_name})").fetchall()
] if row is not None else []

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 Reject unique variants of the registry indexes

When a completed registry has an expected-name index recreated as UNIQUE with the same columns, this verification still reports an exact healthy schema because PRAGMA index_info does not expose uniqueness. For example, a unique scope index passes this check but makes the second reference issued for the same kind and scope fail with UNIQUE constraint failed, rather than failing closed during authority validation; also inspect the index-list uniqueness and partial flags.

Useful? React with 👍 / 👎.

Comment thread retrieval_references.py
Comment on lines +189 to +192
return json.dumps(
value,
ensure_ascii=False,
allow_nan=False,

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 Reject unpaired surrogates during canonicalization

When a binding contains an unpaired surrogate decoded from input such as "\ud800", ensure_ascii=False returns a Python JSON string containing that surrogate instead of rejecting it. Issuance passes the authorization boundary and then fails with an uncaught UnicodeEncodeError when SQLite encodes the value as UTF-8, rather than returning the promised typed invalid_request; reject non-scalar Unicode values during canonicalization or serialize them safely.

Useful? React with 👍 / 👎.

@100yenadmin

Copy link
Copy Markdown
Contributor Author

Closing in favour of #505, the maintenance roll-up — this is commit 2 of that stack.

Nothing is dropped — the commits are carried across unchanged, so the review history here stays meaningful and the work is not rewritten. The consolidation is packaging: a system-level change reads better as one ordered stack than as several PRs that have to be merged in the right sequence to make sense.

Apologies for the churn on your queue.

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