Skip to content

HW-10: add canonical registry-v2 identity and drift detection#154

Closed
skylarbpayne wants to merge 3 commits into
mainfrom
remediation/hw-10
Closed

HW-10: add canonical registry-v2 identity and drift detection#154
skylarbpayne wants to merge 3 commits into
mainfrom
remediation/hw-10

Conversation

@skylarbpayne

@skylarbpayne skylarbpayne commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Scope

Implements the issue-owned canonical registry-v2 catalog contract on exact framework base 4bcc29073668b7275d72bff2e341f0ab52899fb9.

Head: 912e4ba4431201150fbf7a3ac31c5007a9e7d636

Exact seven paths:

  • src/hermes_workflows/registry_v2.py
  • tests/test_registry_v2_contract.py
  • tests/contracts/test_registry_consumer_contract.py
  • tests/fixtures/registry_v2_valid.json
  • tests/fixtures/registry_v2_drift.json
  • tests/fixtures/registry_v1_legacy.json
  • docs/contracts/registry-v2.md

No consumer adapter, shared registry/CLI/plugin/worker/status path, Palmer path, or live state was changed.

Contract

  • Exact registry-v2 schema: schema_version, state_root, object-form dbs, canonical workflows.workflow_ref, and explicit runner policy.
  • Registry-directory → state-root → relative-DB resolution through FND-REGLOC.
  • Deterministic canonical JSON fingerprint and path-redacted public registry/DB identity.
  • Alias-only public resolution and one FND-OP registry.identity service contract for future CLI/plugin/supervisor adapters.
  • Drift refusal for changed catalogs and two similarly named copy-local DBs.
  • One-release read-only v1 parser plus deterministic v1→v2 dry-run; there is no write/apply API.
  • Bounded, redacted FND-OP-style errors with doctor exit code 2.
  • Duplicate/malformed IDs, alternate spellings, traversal, symlink/root escape, unstable files, non-finite JSON, and oversized inputs fail closed.

TDD receipt

Expected red observed on both runtimes before registry_v2.py existed:

Python 3.9:  ModuleNotFoundError: No module named 'hermes_workflows.registry_v2' (2 collection errors)
Python 3.12: ModuleNotFoundError: No module named 'hermes_workflows.registry_v2' (2 collection errors)

Green:

Python 3.12 focused + FND-REGLOC/existing registry: 68 passed in 0.63s
Python 3.12 full at final head: 795 passed, 2 skipped in 55.01s
Python 3.11 full at final head: 795 passed, 2 skipped in 61.29s
Python 3.9 focused + FND-REGLOC/existing registry: 68 passed in 0.14s
Python 3.9 full at final head: 796 passed, 1 skipped in 68.82s
python -m py_compile: pass
git diff --check: pass

The first GitHub Python 3.11 run caught a version-specific dataclass default rejection. Commit 912e4ba4431201150fbf7a3ac31c5007a9e7d636 replaced the shared MappingProxyType default with field(default_factory=...); Python 3.9, 3.11, and 3.12 full suites then passed at the final head.

V1 → v2 dry-run JSON

{"schema_version":1,"source_schema_version":1,"target_fingerprint":"sha256:4a350fb22b93fc5da90ecb45d80fb98961835b1a6ccd79bccb2e03dcbb61e3c8","target_registry":{"dbs":{"audit":{"path":"audit/workflows.sqlite"},"primary":{"path":"primary/workflows.sqlite"}},"runner":{"dbs":["audit","primary"],"lease_seconds":30},"schema_version":2,"state_root":"state","workflows":{"audit-workflow":{"db":"audit","tags":["audit","review"],"title":"Audit workflow","workflow_ref":"example_workflows.audit:audit_workflow"},"review-workflow":{"db":"primary","default_input":{"mode":"review"},"defaults_overlay":"local","description":"A deterministic registry-v2 contract fixture.","tags":["review","workflow"],"title":"Review workflow","trusted_resume":true,"workflow_ref":"example_workflows.review:review_workflow"}}},"target_schema_version":2,"would_write":false}

The source fixture bytes were unchanged before/after this dry run.

Consumer parity JSON

One temp-root service returned the exact same object to simulated CLI/plugin/supervisor consumers:

{"db_alias":"primary","registry_fingerprint":"sha256:4a350fb22b93fc5da90ecb45d80fb98961835b1a6ccd79bccb2e03dcbb61e3c8","registry_identity":"sha256:9daee56a4bca8b986fedc57e3ce0c61257eb3e6c582ef70c7cca01850a9b44d2","resolved_db_identity":"sha256:89cefd5f6899b52a49ce457513746d6910b8b0ef02f5843fd8e1a948b26945d5","schema_version":1}

No registry path, DB filename, workflow defaults, or secret/private value is present.

Drift, redaction, and traversal evidence

{"drift":{"code":"registry_drift","conflict_id":null,"exit_code":2,"fields":{"consumers":["cli","supervisor"]},"message":"registry consumers do not share one registry identity"},"redaction":{"db_filename_absent":true,"private_temp_root_absent":true},"traversal":{"code":"registry_invalid","conflict_id":null,"exit_code":2,"fields":{},"message":"registry does not satisfy the canonical registry-v2 contract"}}

Tests also cover registry-file symlinks, state-root symlinks, DB-component symlinks, absolute/home/drive/backslash paths, parent traversal, duplicate JSON keys, duplicate runner IDs, unknown DB references, raw public paths, and bounded secret-free diagnostics.

Fixture SHA-256

e193374a45246e39ba1e831bb75be469bf805f7cd4cec950a05104f34cb6902e  tests/fixtures/registry_v2_valid.json
50ea41763ed7afa86d61bd2a7dcaf8f66183e7661260cb942917e724590bf105  tests/fixtures/registry_v2_drift.json
1a2f482b861789251d5aec17aaf625d067fae11456c0ef30a541a1b3a41d141a  tests/fixtures/registry_v1_legacy.json

Immutable prerequisites and non-mutation receipt

  • Required FND-REGLOC merge ad9e83091d72cab2f79b8324944d1dea4b740951 remains an ancestor.
  • Excluded PR feat: support custom select values in review queue #131 head fc9eb5ae0797c5cbdfcf51d6b9be551e6ba85331 is not an ancestor.
  • Consumed Palmer INT-P2 PR docs: define runtime vs skills boundary #11 reviewed head 6d77e020f4c7c7974491a985fc764c449163c643, qualified merge/current-main f1fc35148721d57224a3286f02f6537f05d21eaf, for the documented registry-file/state-root/relative-DB relocation boundary only.
  • All execution used immutable fixtures and temporary roots.
  • No live registry, DB, profile, plugin, service, supervisor, cron, package install, restart, deploy, cutover, or migration was read or mutated.

Do not merge before the controller-owned independent SR and separate QR.

@skylarbpayne

Copy link
Copy Markdown
Owner Author

Closing unmerged pending a ground-up reassessment of the remediation scope and process. Do not continue this execution plan.

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