Skip to content

fix(ceg): close CEG-001..009 from the Constellation E2E action log - #283

Closed
cryptoxdog wants to merge 3 commits into
mainfrom
claude/action-items-alignment-l8lwfl
Closed

cryptoxdog wants to merge 3 commits into
mainfrom
claude/action-items-alignment-l8lwfl

Conversation

@cryptoxdog

Copy link
Copy Markdown
Collaborator

Problem

fix(ceg): close CEG-001..009 from the Constellation E2E action log (+1 more commit below)

CEG-001 supply chain. The release set kept the moving @v1 tag and closed the finding on the lock instead: poetry.lock records resolved_reference e9f829f, which is what every deployed image installs, and validate_sdk_pin.py now prints that commit on PASS so a build log says which SDK object was taken. EIE's validator enforces the same contract over its requirements.lock. The trade-off the moving tag accepts — a live-resolving build takes whatever v1 points at that minute — is now stated in the script rather than left to be discovered.

Closes #

Fix

  • fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • fix(ceg): repair kernel-surfaced drift from the CEG-007 removal

Risk

  • Low — additive, reversible, no data or contract change — n/a — not this change
  • Medium — touches shared code, config, or a public interface
  • High — breaking change, migration, IAM/network, or irreversible — n/a — not this change

Blast radius: measured paths in Changes by intent
Rollback: revert this PR

Evidence

gate-receipt.json present: schema=l9.pr_gate_receipt.v2 content_digest=1480292684 passed_at=2026-09-19T18:19:52Z
L4 receipt present: phase=release_authorized tree_digest=3a895d046d67e447ca99c713bf80be2ecc20af4dde56d1583e035e718e2f0994 kernel_evidence=evidenced

Gates

  • Regression test added that fails without this fix — n/a — not this change
  • No secrets, tokens, or customer data in code, tests, fixtures, or logs
  • semgrep clean, or findings triaged below — n/a — not this change
  • New IAM / workflow permissions are least privilege and enumerated — n/a — not this change
  • Third-party actions pinned to a full commit SHA — n/a — not this change
  • Public interface change is documented and versioned — n/a — not this change
  • Observability exists for the new path (metric, log, trace, or alert) — n/a — not this change

Reviewer focus

See Changes by intent and Protected-root (if any additive_only path).

Changes by intent

Added

  • tests/unit/test_domain_database_provisioning.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • tests/unit/test_domain_pack_shape.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • tests/unit/test_graph_inference_egress.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log

Modified

  • .claude/rules/capability-registry.md — fix(ceg): repair kernel-surfaced drift from the CEG-007 removal
  • .claude/rules/feature-flags.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • .claude/rules/subsystems.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • .env.template — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • .github/workflows/ci-quality.yml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • .github/workflows/ci.yml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • AGENTS.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • Makefile — fix(ceg): repair kernel-surfaced drift from the CEG-007 removal
  • README.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • Readme-Requirements.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • chassis/auth/settings.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • docker-compose.prod.yml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • docker-compose.yml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • docs/CI_PIPELINE.md — fix(ceg): repair kernel-surfaced drift from the CEG-007 removal
  • docs/DEPLOYMENT.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • docs/FEATURE_GATES.md — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • docs/contracts/config/env-contract.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/aios-god-agent/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/executive-assistant/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/freight-matching/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/healthcare-referral/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/legal-discovery/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/mortgage-brokerage/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/repo-as-agent/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/research-agent/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • domains/roofing-company/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • engine/config/settings.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • engine/gate_egress.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • engine/graph/driver.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • engine/handlers.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • engine/spec.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • poetry.lock — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • pyproject.toml — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • requirements.txt — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • scripts/validate_sdk_pin.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • templates/.env.recommended.template — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • tests/contracts/_constants.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • tests/contracts/conftest.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • tests/contracts/test_dependency_contracts.py — fix(ceg): close CEG-001..009 from the Constellation E2E action log

Deleted

  • docs/contracts/dependencies/redis.yaml — fix(ceg): close CEG-001..009 from the Constellation E2E action log

Files touched

  • M .claude/rules/capability-registry.md
  • M .claude/rules/feature-flags.md
  • M .claude/rules/subsystems.md
  • M .env.template
  • M .github/workflows/ci-quality.yml
  • M .github/workflows/ci.yml
  • M AGENTS.md
  • M Makefile
  • M README.md
  • M Readme-Requirements.md
  • M chassis/auth/settings.py
  • M docker-compose.prod.yml
  • M docker-compose.yml
  • M docs/CI_PIPELINE.md
  • M docs/DEPLOYMENT.md
  • M docs/FEATURE_GATES.md
  • M docs/contracts/config/env-contract.yaml
  • D docs/contracts/dependencies/redis.yaml
  • R100 domains/aios_god_agent_domain_spec.yaml domains/aios-god-agent/spec.yaml
  • R088 domains/executive_assistant_domain_spec.yaml domains/executive-assistant/spec.yaml
  • R100 domains/freight_matching_domain_spec.yaml domains/freight-matching/spec.yaml
  • R100 domains/healthcare_referral_domain_spec.yaml domains/healthcare-referral/spec.yaml
  • R100 domains/legal_discovery_domain_spec.yaml domains/legal-discovery/spec.yaml
  • R100 domains/mortgage_brokerage_domain_spec.yaml domains/mortgage-brokerage/spec.yaml
  • R100 domains/repo_as_agent_domain_spec.yaml domains/repo-as-agent/spec.yaml
  • R100 domains/research_agent_domain_spec.yaml domains/research-agent/spec.yaml
  • R087 domains/roofing_company_domain_spec.yaml domains/roofing-company/spec.yaml
  • M engine/config/settings.py
  • M engine/gate_egress.py
  • M engine/graph/driver.py
  • M engine/handlers.py
  • M engine/spec.yaml
  • M poetry.lock
  • M pyproject.toml
  • M requirements.txt
  • M scripts/validate_sdk_pin.py
  • M templates/.env.recommended.template
  • M tests/contracts/_constants.py
  • M tests/contracts/conftest.py
  • M tests/contracts/test_dependency_contracts.py
  • A tests/unit/test_domain_database_provisioning.py
  • A tests/unit/test_domain_pack_shape.py
  • A tests/unit/test_graph_inference_egress.py

Commits

  • fix(ceg): close CEG-001..009 from the Constellation E2E action log
  • fix(ceg): repair kernel-surfaced drift from the CEG-007 removal

Test plan

  • make pr local gate receipt present
  • L4 release receipt present (release_authorized)
  • CI green — not measured by open_pr_after_gate.sh — do not treat as verified

Changed files

  • M .claude/rules/capability-registry.md
  • M .claude/rules/feature-flags.md
  • M .claude/rules/subsystems.md
  • M .env.template
  • M .github/workflows/ci-quality.yml
  • M .github/workflows/ci.yml
  • M AGENTS.md
  • M Makefile
  • M README.md
  • M Readme-Requirements.md
  • M chassis/auth/settings.py
  • M docker-compose.prod.yml
  • M docker-compose.yml
  • M docs/CI_PIPELINE.md
  • M docs/DEPLOYMENT.md
  • M docs/FEATURE_GATES.md
  • M docs/contracts/config/env-contract.yaml
  • D docs/contracts/dependencies/redis.yaml
  • R100 domains/aios_god_agent_domain_spec.yaml domains/aios-god-agent/spec.yaml
  • R088 domains/executive_assistant_domain_spec.yaml domains/executive-assistant/spec.yaml
  • R100 domains/freight_matching_domain_spec.yaml domains/freight-matching/spec.yaml
  • R100 domains/healthcare_referral_domain_spec.yaml domains/healthcare-referral/spec.yaml
  • R100 domains/legal_discovery_domain_spec.yaml domains/legal-discovery/spec.yaml
  • R100 domains/mortgage_brokerage_domain_spec.yaml domains/mortgage-brokerage/spec.yaml
  • R100 domains/repo_as_agent_domain_spec.yaml domains/repo-as-agent/spec.yaml
  • R100 domains/research_agent_domain_spec.yaml domains/research-agent/spec.yaml
  • R087 domains/roofing_company_domain_spec.yaml domains/roofing-company/spec.yaml
  • M engine/config/settings.py
  • M engine/gate_egress.py
  • M engine/graph/driver.py
  • M engine/handlers.py
  • M engine/spec.yaml
  • M poetry.lock
  • M pyproject.toml
  • M requirements.txt
  • M scripts/validate_sdk_pin.py
  • M templates/.env.recommended.template
  • M tests/contracts/_constants.py
  • M tests/contracts/conftest.py
  • M tests/contracts/test_dependency_contracts.py
  • A tests/unit/test_domain_database_provisioning.py
  • A tests/unit/test_domain_pack_shape.py
  • A tests/unit/test_graph_inference_egress.py

Generated by Claude Code

CEG-001 supply chain. The release set kept the moving @v1 tag and closed the
finding on the lock instead: poetry.lock records resolved_reference e9f829f,
which is what every deployed image installs, and validate_sdk_pin.py now prints
that commit on PASS so a build log says which SDK object was taken. EIE's
validator enforces the same contract over its requirements.lock. The trade-off
the moving tag accepts — a live-resolving build takes whatever v1 points at
that minute — is now stated in the script rather than left to be discovered.

CEG-002 configuration. Both compose files set L9_REQUIRE_SIGNATURE=true and
neither set L9_VERIFYING_KEYS_JSON. That flag also verifies the responses Gate
signs, and Gate signs with its own key id, so as shipped CEG rejected every
signed Gate response — the E2E passed only because its harness supplied the
map. Dev carries the shared HMAC secret; prod requires the variable rather than
defaulting it, because a wrong key here is a silent trust failure.

CEG-003 configuration. Compose set L9_NODE_SPEC_PATH, which nothing reads. The
SDK reads GATE_NODE_SPEC_PATH. Registration worked only because the SDK default
happens to be engine/spec.yaml and WORKDIR is /app, so relocating the spec
would have silently had no effect until the default path stopped existing — at
which point register_with_gate swallows FileNotFoundError and returns False.

CEG-005 architecture. engine/spec.yaml now declares owner: ceg. Registration
previously succeeded only because Gate's _OWNER_ALIASES maps the node name
"graph" to "ceg": correct today, and an alias rather than a declaration.
Renaming the node would have broken registration for every canonical action at
once. Pairs with the resolve ownership entry added in Constellation.Gate.

CEG-006 + EIE-008 architecture. Two halves of one loop, neither connected.
engine/health/api.py implemented three handlers and was imported by nothing, so
request_enrichment — the entire CEG -> Gate -> EIE direction — had no trigger an
inbound packet could reach; it now hangs off `admin` alongside trigger_gds,
where operator surfaces belong. In the other direction EIE advertises and fully
implements `graph-inference-result` and no code here ever produced one, so the
feedback loop had a consumer and no producer. emit_graph_inference_result sends
it through Gate, filtering at the same 0.55 confidence floor EIE drops below —
the two sides were built to the same number and never joined. Flag-gated
(GRAPH_INFERENCE_FEEDBACK_ENABLED), because each emission spends EIE budget.

CEG-007 dependency hygiene. No import of redis exists anywhere under engine/ or
chassis/, yet redis was a requirement, a service in both compose files with
depends_on: service_healthy (so the api service could not start without it), a
CI service container in two workflows, a required env var in the env contract,
and a dependency contract claiming "Scoring result caching" and "Domain pack
cache" that were never implemented. Four contract tests asserted that
description continuously, which is what made an unused dependency look
load-bearing. All of it removed together.

CEG-008 operability. match and sync route to a Neo4j database named after the
domain id and nothing created it, so on a fresh instance every one failed until
an operator ran CREATE DATABASE by hand. GraphDriver now provisions it on first
use under AUTO_CREATE_DOMAIN_DATABASE (once per database per process,
Enterprise-only), and either way an absent database raises
DatabaseNotProvisionedError naming the database and the exact command. The name
is validated before it is quoted into the statement: CREATE DATABASE takes no
query parameter, and sanitize_label cannot be used because domain ids
legitimately contain dashes.

CEG-009 configuration. Nine specs used a flat <name>_domain_spec.yaml shape the
loader never reads — it resolves domains/<domain_id>/spec.yaml — so they looked
like available verticals and no tenant id could select them. Migrated. Two were
additionally invalid, with edges to undeclared Skill and ZipCode nodes; nothing
caught that, because a file the loader never opens is never validated either.
Loadable domains go from one to ten, idea-portfolio still behind its flag.

Verification: 1818 passed, 12 skipped, 56 xfailed across unit, contracts,
compliance, architecture and invariants. Contract 21 caught the new feature
flag as undocumented and FEATURE_GATES.md now carries both new gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoomAnwQt9gxGhHAJJSDz2
Recursive Alignment found the redis removal stopped at the declarations. The
Makefile still drove the service: `health` exec'd l9-graph-redis, `redis-shell`
opened a CLI on a container that no longer exists, `local-dbs` ran
`docker compose up -d neo4j redis` against a service absent from both compose
files, and two local-api targets exported PLASTICOS_REDIS_URL for a setting
that was deleted. docs/CI_PIPELINE.md still listed the CI redis service.

Also registered the three capabilities this branch adds in
.claude/rules/capability-registry.md. CLAUDE.md's first "Always" is to check
that registry before building, so a capability missing from it is how a second
implementation gets written — which is exactly what EIE-006 turned out to be.

Apply report: .l9/autonomy/kernel-apply.md. Suites unchanged at 1818 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoomAnwQt9gxGhHAJJSDz2
Copilot AI lite review requested due to automatic review settings September 19, 2026 18:19
@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown

PR Too Large
Reviewable additions: 1251
Limit: 1000 added lines
(deletions: 221; total churn 1472 is warn-only)
Action Required: Break into smaller, atomic PRs

📋 Best Practices for Large Changes

  1. Refactoring + Features: Separate into 2 PRs
  2. Multiple Features: One PR per feature
  3. Database + Code: Separate migration from logic
  4. Generated Code: Exclude it from reviewable-size accounting

🚫 This PR is blocked until reviewable size limits are met.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-19T18:27:14.634561Z 7ecf4ec PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown

L9 Audit Harness Report

  • Generated: 2026-09-19T18:43:16.607067+00:00
  • Repo root: /home/runner/work/Cognitive.Engine.Graphs/Cognitive.Engine.Graphs
  • Overall result: ✅ PASSED
  • Exit code: 0

Step Results

Step Status Exit Code Notes
Architecture Audit ✅ Passed 0
Spec Coverage ✅ Passed 0
Contract Wiring ✅ Passed 0

Architecture Audit Findings

Severity Count
🔴 CRITICAL 0
🟠 HIGH 0
🟡 MEDIUM 17
🔵 LOW 0

See artifacts/audit_report.md for full details.

Spec Coverage

  • ✅ Implemented: 37
  • ⚠️ Partial: 9
  • ❌ Missing: 0
  • Total features: 46
Category Implemented Partial Missing Total
gates 10 0 0 10
scoring 7 0 0 7
v1.1_node 2 0 0 2
v1.1_edge 2 0 0 2
v1.1_action 0 2 0 2
v1.1_scoring 1 1 0 2
action_handler 0 6 0 6
gds_algorithm 5 0 0 5
research_pattern 10 0 0 10

See artifacts/coverage_report.md for full details.

Next Steps

All checks passed. Safe to merge.

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

A few newly introduced runtime behaviors have concrete correctness gaps (exception handling and payload parsing) that should be fixed before approval.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 3 Medium severity · 1 Low severity

Open (4)
What changed in this PR

This PR addresses multiple Constellation E2E seam findings (CEG-001..009) by removing a non-existent Redis dependency chain, hardening Gate/SDK configuration defaults, migrating domain specs into the loader’s expected layout, and adding new engine capabilities for graph inference feedback and optional Neo4j domain-database provisioning.

Changes:

  • Removed Redis as a declared dependency across code/config/docs/tests (and deleted the Redis dependency contract).
  • Added optional “domain database provisioning” in GraphDriver and an optional “graph inference feedback” egress path via Gate, surfaced through admin subactions and feature flags.
  • Migrated domain specs into domains/<domain_id>/spec.yaml layout and added unit tests to enforce pack shape and validate specs.
File Description
.claude/​rules/​capability-registry.md Documents new/clarified engine capabilities (egress, provisioning, inference rules).
.claude/​rules/​feature-flags.md Documents new feature flags for inference feedback and DB provisioning.
.claude/​rules/​subsystems.md Documents new admin subactions for health and inference feedback.
.env.template Removes Redis env var; documents correct Gate spec env var and verifying keys.
.github/​workflows/​ci-quality.yml Removes Redis service/env wiring from CI quality workflow.
.github/​workflows/​ci.yml Removes Redis service/env wiring from CI workflow.
AGENTS.md Updates repo command/docs references to remove Redis from local stack.
Makefile Removes Redis health/shell targets; updates local DB target to Postgres.
README.md Updates architecture and env var docs to remove Redis references.
Readme-Requirements.md Removes Redis references from requirements doc.
chassis/​auth/​settings.py Removes unused redis_url setting from chassis settings.
docker-compose.prod.yml Removes Redis service and wiring; corrects Gate spec env var; adds verifying-keys requirement.
docker-compose.yml Removes Redis service and wiring; corrects Gate spec env var; adds verifying-keys map.
docs/​CI_PIPELINE.md Removes Redis from CI pipeline documentation.
docs/​DEPLOYMENT.md Removes Redis from deployment docs/diagrams and env examples.
docs/​FEATURE_GATES.md Documents the new GRAPH_INFERENCE_FEEDBACK_ENABLED and AUTO_CREATE_DOMAIN_DATABASE flags.
docs/​contracts/​config/​env-contract.yaml Removes required Redis env contract and documents why.
docs/​contracts/​dependencies/​redis.yaml Deleted Redis dependency contract.
domains/​aios-god-agent/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​executive-assistant/​spec.yaml Migrated spec; adds missing Skill node to satisfy edge references.
domains/​freight-matching/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​healthcare-referral/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​legal-discovery/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​mortgage-brokerage/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​repo-as-agent/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​research-agent/​spec.yaml Migrated domain spec into loader-friendly directory structure.
domains/​roofing-company/​spec.yaml Migrated spec; adds missing ZipCode node to satisfy edge references.
engine/​config/​settings.py Removes Redis config; adds feature flags for DB provisioning and inference feedback.
engine/​gate_egress.py Adds graph-inference-result egress with output shaping, floor filtering, idempotency key, and dispatch.
engine/​graph/​driver.py Adds DB-name validation, absent-db detection, optional auto-create-on-first-use, and better missing-db error.
engine/​handlers.py Adds reachable health_* admin subactions and emit_inference_feedback admin subaction (flag-gated).
engine/​spec.yaml Declares node owner explicitly for Gate registration/ownership assertions.
poetry.lock Removes Redis package; updates lock metadata.
pyproject.toml Removes Redis dependency.
requirements.txt Removes Redis dependency.
scripts/​validate_sdk_pin.py Prints resolved SDK commit SHA from lock on PASS.
templates/​.env.recommended.template Removes Redis env var.
tests/​contracts/​_constants.py Removes REDIS_URL from required env var list.
tests/​contracts/​conftest.py Removes Redis dependency fixture.
tests/​contracts/​test_dependency_contracts.py Removes Redis contract tests and updates file purpose.
tests/​unit/​test_domain_database_provisioning.py Adds unit coverage for DB provisioning behavior and error messaging.
tests/​unit/​test_domain_pack_shape.py Adds tests enforcing domain pack structure and spec validity/loadability.
tests/​unit/​test_graph_inference_egress.py Adds unit tests for inference-output shaping, idempotency, and Gate dispatch behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread engine/gate_egress.py Outdated
Comment thread engine/graph/driver.py
Comment thread engine/handlers.py
Comment thread scripts/validate_sdk_pin.py Outdated

@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

type: traversal
pattern: "candidate-[:HAS_SKILL]->(s:Skill)<-[:REQUIRES]-(query)"
condition: "s IS NOT NULL"

P1 Badge Compile traversal patterns before activating domain packs

For every match using the newly discoverable executive-assistant pack, GateCompiler._compile_traversal() ignores both pattern and condition; because this gate supplies no edgetype, it compiles to exists((candidate)-[:RELATES_TO]->(t)) instead of the declared HAS_SKILL path. The ontology and sync configuration define no RELATES_TO edge, so the hard gate rejects all normally populated candidates. The same unsupported shape appears in the newly activated aios-god-agent and repo-as-agent packs; either safely compile these patterns or express them in fields the compiler consumes.

AGENTS.md reference: AGENTS.md:L118-L120



P1 Badge Replace scalar query parameters with executable gate values

When tasktoexpert is matched, Pydantic coerces this scalar to the string "85.0", and the threshold compiler interpolates it as a parameter name, producing candidate.currentutilizationpct <= $85.0; that is not a parameter supplied by the resolved query and is not valid as the intended numeric literal, so this newly activated domain fails during Cypher execution. Several other migrated packs use the same scalar-queryparam pattern (true, false, 1, or 5), so these constants need explicit compiler support or equivalent query fields before the packs are made discoverable.

AGENTS.md reference: AGENTS.md:L118-L120

ℹ️ 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 engine/handlers.py
Comment thread engine/handlers.py
Comment thread engine/config/settings.py
Nine findings from the PR #283 review plus the single mypy error that
turned all four CEG lint jobs red.

CI fix
- handlers.py: the inference-rule walrus reused `result`, already bound to
  dict[str, Any] earlier in handle_admin. Renamed to `inferred`.
  mypy: "Success: no issues found in 133 source files".

Correctness
- graph/driver.py: ensure_database() claimed the database name AFTER the
  await, so concurrent first-use requests each issued their own CREATE
  DATABASE. The claim now precedes the suspension point and is released on
  failure so a later attempt can retry.
- handlers.py: `rules: []` in emit_inference_feedback silently became "run
  every rule"; a bare string was iterated character by character. Absent
  key still means all rules; a non-list of non-strings is now rejected.
- gate_egress.py: get_gate_client() raises ValueError on missing or invalid
  SDK environment material. Both egress paths caught only GateClientError,
  so a configuration fault crashed the caller instead of returning the
  typed failure result every other path returns.
- health/health_report.py: _conversion_events was an unbounded list fed by
  every Seed-tier assess/report call — a leak CEG-006 made reachable, and
  one CLAUDE.md's "never create unbounded caches" covers. Now a
  deque(maxlen=10_000).
- scripts/validate_sdk_pin.py: printed "PASS ... -> None" when the tree has
  no poetry.lock. Says what is true instead.

Feature-flag discipline (C-21)
- health_* admin subactions now gate on health_api_enabled. auto_enrich_via_gate
  gates only the outbound Gate request, not assessment, reporting or
  conversion tracking, so the surface needed its own flag.
- admin feature_status reports all five Constellation-seam flags.

Domain packs — correction to the PR body
- Five of the nine packs CEG-009 made readable compile to Cypher that
  cannot execute: `type: traversal` gates written with pattern/condition
  fall back to a RELATES_TO edge no ontology declares, and scalar
  queryparams (85.0, 5, 1) are emitted as parameter NAMES, producing $85.0.
  Readable is not correct. They are gated behind
  unvalidated_domain_packs_enabled until the compiler or query schema grows
  the support they assume.
- The PR's "loadable domains 1 -> 10" is therefore
  "1 -> 5 discoverable-and-executable, plus 5 migrated-but-dormant".
- test_domain_pack_shape.py compiles every discoverable pack's gates and
  fails on either defect shape; a shrink-only test fails if a gated pack
  starts compiling cleanly, so the flag cannot become a place defects go to
  be forgotten.

Verification
- pytest tests/unit tests/contracts tests/compliance tests/architecture
  tests/invariants: exit 0 (jsonschema installed so the two previously
  skipped contract modules actually ran: 34 passed).
- mypy engine/: clean. ruff check/format clean on changed files under the
  CI-pinned rule set.
- tools/contract_scanner.py: no violations. tools/verify_contracts.py: 27/27.
- scripts/validate_sdk_pin.py: PASS Quantum-L9/Gate_SDK@v1 -> e9f829f.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoomAnwQt9gxGhHAJJSDz2
@sonarqubecloud

Copy link
Copy Markdown

Copy link
Copy Markdown
Collaborator Author

CI is green except the size gate — and a correction to this PR's own claim

Remediation on e2075e7

All four lint jobs were red from one mypy error: the inference-rule walrus in handle_admin reused result, already bound to dict[str, Any] earlier in the function. Renamed to inferred — not by loosening the annotation. mypy engine/: Success: no issues found in 133 source files. CI now reports 56 of 57 checks passing; SonarCloud Quality Gate passed and the L9 Audit Harness passed with 0 critical / 0 high.

Nine review findings addressed. The substantive ones:

  • GraphDriver.ensure_database() race — the database name was claimed after the await, so every request that arrived while the first CREATE DATABASE was in flight passed the membership check and issued its own administrative command. "At most once per database per process" held only when calls did not overlap, which is exactly when it does not matter. The claim now precedes the suspension point and is released on failure so a later attempt can retry.
  • emit_inference_feedbackrules: [] silently became "run every rule", and a bare string was iterated character by character with each char looked up as a rule name. Absent key still means all rules; a non-list of non-strings is now rejected.
  • gate_egressget_gate_client() raises ValueError on missing or invalid SDK environment material. Both egress paths caught only GateClientError, so a configuration fault crashed the caller instead of returning the typed failure result every other path in the module returns.
  • _conversion_events — an unbounded list fed by every Seed-tier assess/report call, which CEG-006 had just made reachable. Now deque(maxlen=10_000).
  • C-21 — the health_* admin subactions now gate on health_api_enabled. auto_enrich_via_gate gates only the outbound Gate request, not assessment, reporting or conversion tracking, so the surface needed its own flag.

Correction: "loadable domains 1 → 10" was wrong

CEG-009 moved nine domain packs into the shape the loader reads, and I reported the result as ten discoverable domains. That counted files the loader can open, not packs it can serve. Five of them compile to Cypher that cannot execute:

  • type: traversal gates written with pattern + condition, which GateCompiler does not consume — with no edgetype they fall back to RELATES_TO, an edge no ontology here declares, so the gate rejects every candidate;
  • a scalar queryparam (85.0, 5, 1) — GateSpec coerces it to a string and the compiler emits it as a parameter name, producing $85.0.

Validating against DomainSpec proves a pack parses, not that its gates run. The honest number is 1 → 5 discoverable-and-executable, plus 5 migrated-but-dormant behind unvalidated_domain_packs_enabled. tests/unit/test_domain_pack_shape.py now compiles every discoverable pack's gates and fails on either defect shape, and a shrink-only test fails if a gated pack starts compiling cleanly — so the flag cannot become a place defects go to be forgotten. Reaching those five needs either compiler support for pattern/condition and literal operands, or a query-schema parameter per constant. That is a schema decision, not a file move.

Blocking: PR size

Enforce PR Policies is the only failing check: 1251 additions against a 1000 limit. There is no per-PR override in .github/workflows/pr-review-enforcement.yml — the levers are the PR_BLOCK_LINES repo variable or .github/pr_review_config.yaml, both of which weaken the gate for every PR. This needs a maintainer decision: raise the limit, or split. The natural seam is CEG-007 (Redis removal — compose, CI, contracts, lockfile) and CEG-009 (the nine domain-pack moves) as one PR, with CEG-004/006/008 (Gate seam, database provisioning, health surface) as another.

Local verification on e2075e7: pytest tests/unit tests/contracts tests/compliance tests/architecture tests/invariants1858 passed, 16 skipped, 56 xfailed (two contract modules that had been skipping for a missing jsonschema now actually run); tools/contract_scanner.py no violations; tools/verify_contracts.py 27/27; scripts/validate_sdk_pin.py PASS at Quantum-L9/Gate_SDK@v1 -> e9f829f.


Generated by Claude Code

@cryptoxdog

Copy link
Copy Markdown
Collaborator Author

PR Remediation — Cycle 1 Summary

Commit: ea2bdef | Findings processed: 6 | CI gates: NotApplicable (successor #285 already on GitHub; these PRs are closed as superseded, not republished)

Fixed (6)

Finding File Change
F283-1 ensure_database race engine/graph/driver.py in-flight task + shield on #285
rules: [] falsy engine/handlers.py landed on #285
PASS -> None scripts/validate_sdk_pin.py landed on #285
health subactions ungated engine/handlers.py landed on #285 successor review
unbounded conversion events engine/handlers.py landed on #285
feature_status missing flags engine/config/settings.py landed on #285

Deferred (0)

none

Acknowledged (0)

none

Disagreed (0)

none


Local verify: NotApplicable (successor #285 already on GitHub; these PRs are closed as superseded, not republished) | Threads resolved: 6/6

@cryptoxdog

Copy link
Copy Markdown
Collaborator Author

Superseded by #285 — that branch is main plus this PR's content plus the 2026-09-20 audit fixes (F280-1/2, F283-1, F284-1/2). Merging this head would conflict with or undo the successor. Closing so #285 can land.

@cryptoxdog cryptoxdog closed this Sep 21, 2026
cryptoxdog added a commit that referenced this pull request Sep 21, 2026
…ersedes #280, #281, #283, #284) (#285)

* fix(c-009): add make cypher-lint and close live interpolation holes

C-009 named make cypher-lint as automated enforcement but the target did
not exist. Add the scanner, wire it to Make and pre-commit, and
parameterize the live quoted interpolations it now finds.

Issue-Remediation-Cycle: #272/cycle-1
Co-authored-by: Cursor <cursoragent@cursor.com>

* style: commit gate writer rewrites so make pr finishes once

* fix(c-009): return label-safety check as a boolean

Ruff SIM103 failed the PR writer wave on the two-return form.

Issue-Remediation-Cycle: #272/cycle-1
Co-authored-by: Cursor <cursoragent@cursor.com>

* test(c-009): cover cypher_quoted_ident wrap and reject

Carry the isolate follow-up tests onto the open PR so identifier quoting
has the same unit coverage as sanitize_label.

Issue-Remediation-Cycle: #272/cycle-1
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): declare consumer repo_class python for org-ci language detect

CEG is Python-only but had no .l9/ci.json, so REPO_CLASS=auto left Analyze (central Core) fail-closed on ambiguous SDK language detect. Consumer metadata is the documented escape hatch and does not touch workflows.

Issue-Remediation-Cycle: #273/cycle-1
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ceg): close CEG-001..009 from the Constellation E2E action log

CEG-001 supply chain. The release set kept the moving @v1 tag and closed the
finding on the lock instead: poetry.lock records resolved_reference e9f829f,
which is what every deployed image installs, and validate_sdk_pin.py now prints
that commit on PASS so a build log says which SDK object was taken. EIE's
validator enforces the same contract over its requirements.lock. The trade-off
the moving tag accepts — a live-resolving build takes whatever v1 points at
that minute — is now stated in the script rather than left to be discovered.

CEG-002 configuration. Both compose files set L9_REQUIRE_SIGNATURE=true and
neither set L9_VERIFYING_KEYS_JSON. That flag also verifies the responses Gate
signs, and Gate signs with its own key id, so as shipped CEG rejected every
signed Gate response — the E2E passed only because its harness supplied the
map. Dev carries the shared HMAC secret; prod requires the variable rather than
defaulting it, because a wrong key here is a silent trust failure.

CEG-003 configuration. Compose set L9_NODE_SPEC_PATH, which nothing reads. The
SDK reads GATE_NODE_SPEC_PATH. Registration worked only because the SDK default
happens to be engine/spec.yaml and WORKDIR is /app, so relocating the spec
would have silently had no effect until the default path stopped existing — at
which point register_with_gate swallows FileNotFoundError and returns False.

CEG-005 architecture. engine/spec.yaml now declares owner: ceg. Registration
previously succeeded only because Gate's _OWNER_ALIASES maps the node name
"graph" to "ceg": correct today, and an alias rather than a declaration.
Renaming the node would have broken registration for every canonical action at
once. Pairs with the resolve ownership entry added in Constellation.Gate.

CEG-006 + EIE-008 architecture. Two halves of one loop, neither connected.
engine/health/api.py implemented three handlers and was imported by nothing, so
request_enrichment — the entire CEG -> Gate -> EIE direction — had no trigger an
inbound packet could reach; it now hangs off `admin` alongside trigger_gds,
where operator surfaces belong. In the other direction EIE advertises and fully
implements `graph-inference-result` and no code here ever produced one, so the
feedback loop had a consumer and no producer. emit_graph_inference_result sends
it through Gate, filtering at the same 0.55 confidence floor EIE drops below —
the two sides were built to the same number and never joined. Flag-gated
(GRAPH_INFERENCE_FEEDBACK_ENABLED), because each emission spends EIE budget.

CEG-007 dependency hygiene. No import of redis exists anywhere under engine/ or
chassis/, yet redis was a requirement, a service in both compose files with
depends_on: service_healthy (so the api service could not start without it), a
CI service container in two workflows, a required env var in the env contract,
and a dependency contract claiming "Scoring result caching" and "Domain pack
cache" that were never implemented. Four contract tests asserted that
description continuously, which is what made an unused dependency look
load-bearing. All of it removed together.

CEG-008 operability. match and sync route to a Neo4j database named after the
domain id and nothing created it, so on a fresh instance every one failed until
an operator ran CREATE DATABASE by hand. GraphDriver now provisions it on first
use under AUTO_CREATE_DOMAIN_DATABASE (once per database per process,
Enterprise-only), and either way an absent database raises
DatabaseNotProvisionedError naming the database and the exact command. The name
is validated before it is quoted into the statement: CREATE DATABASE takes no
query parameter, and sanitize_label cannot be used because domain ids
legitimately contain dashes.

CEG-009 configuration. Nine specs used a flat <name>_domain_spec.yaml shape the
loader never reads — it resolves domains/<domain_id>/spec.yaml — so they looked
like available verticals and no tenant id could select them. Migrated. Two were
additionally invalid, with edges to undeclared Skill and ZipCode nodes; nothing
caught that, because a file the loader never opens is never validated either.
Loadable domains go from one to ten, idea-portfolio still behind its flag.

Verification: 1818 passed, 12 skipped, 56 xfailed across unit, contracts,
compliance, architecture and invariants. Contract 21 caught the new feature
flag as undocumented and FEATURE_GATES.md now carries both new gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoomAnwQt9gxGhHAJJSDz2

* fix(ceg): repair kernel-surfaced drift from the CEG-007 removal

Recursive Alignment found the redis removal stopped at the declarations. The
Makefile still drove the service: `health` exec'd l9-graph-redis, `redis-shell`
opened a CLI on a container that no longer exists, `local-dbs` ran
`docker compose up -d neo4j redis` against a service absent from both compose
files, and two local-api targets exported PLASTICOS_REDIS_URL for a setting
that was deleted. docs/CI_PIPELINE.md still listed the CI redis service.

Also registered the three capabilities this branch adds in
.claude/rules/capability-registry.md. CLAUDE.md's first "Always" is to check
that registry before building, so a capability missing from it is how a second
implementation gets written — which is exactly what EIE-006 turned out to be.

Apply report: .l9/autonomy/kernel-apply.md. Suites unchanged at 1818 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoomAnwQt9gxGhHAJJSDz2

* fix(ceg): remediate PR #283 review findings and mypy CI failure

Nine findings from the PR #283 review plus the single mypy error that
turned all four CEG lint jobs red.

CI fix
- handlers.py: the inference-rule walrus reused `result`, already bound to
  dict[str, Any] earlier in handle_admin. Renamed to `inferred`.
  mypy: "Success: no issues found in 133 source files".

Correctness
- graph/driver.py: ensure_database() claimed the database name AFTER the
  await, so concurrent first-use requests each issued their own CREATE
  DATABASE. The claim now precedes the suspension point and is released on
  failure so a later attempt can retry.
- handlers.py: `rules: []` in emit_inference_feedback silently became "run
  every rule"; a bare string was iterated character by character. Absent
  key still means all rules; a non-list of non-strings is now rejected.
- gate_egress.py: get_gate_client() raises ValueError on missing or invalid
  SDK environment material. Both egress paths caught only GateClientError,
  so a configuration fault crashed the caller instead of returning the
  typed failure result every other path returns.
- health/health_report.py: _conversion_events was an unbounded list fed by
  every Seed-tier assess/report call — a leak CEG-006 made reachable, and
  one CLAUDE.md's "never create unbounded caches" covers. Now a
  deque(maxlen=10_000).
- scripts/validate_sdk_pin.py: printed "PASS ... -> None" when the tree has
  no poetry.lock. Says what is true instead.

Feature-flag discipline (C-21)
- health_* admin subactions now gate on health_api_enabled. auto_enrich_via_gate
  gates only the outbound Gate request, not assessment, reporting or
  conversion tracking, so the surface needed its own flag.
- admin feature_status reports all five Constellation-seam flags.

Domain packs — correction to the PR body
- Five of the nine packs CEG-009 made readable compile to Cypher that
  cannot execute: `type: traversal` gates written with pattern/condition
  fall back to a RELATES_TO edge no ontology declares, and scalar
  queryparams (85.0, 5, 1) are emitted as parameter NAMES, producing $85.0.
  Readable is not correct. They are gated behind
  unvalidated_domain_packs_enabled until the compiler or query schema grows
  the support they assume.
- The PR's "loadable domains 1 -> 10" is therefore
  "1 -> 5 discoverable-and-executable, plus 5 migrated-but-dormant".
- test_domain_pack_shape.py compiles every discoverable pack's gates and
  fails on either defect shape; a shrink-only test fails if a gated pack
  starts compiling cleanly, so the flag cannot become a place defects go to
  be forgotten.

Verification
- pytest tests/unit tests/contracts tests/compliance tests/architecture
  tests/invariants: exit 0 (jsonschema installed so the two previously
  skipped contract modules actually ran: 34 passed).
- mypy engine/: clean. ruff check/format clean on changed files under the
  CI-pinned rule set.
- tools/contract_scanner.py: no violations. tools/verify_contracts.py: 27/27.
- scripts/validate_sdk_pin.py: PASS Quantum-L9/Gate_SDK@v1 -> e9f829f.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CoomAnwQt9gxGhHAJJSDz2

* fix(ci): restore L9 analysis and settle Protocol body + Scorecard GHCR

Restore the owner-managed l9-analysis.yml deleted in #262. Keep Scorecard
on GHCR-backed v2.4.4 (v2.4.0 still pulls gcr.io/openssf). Protocol
methods are docstring-only so STUB-001, ruff, and code-quality agree.

Issue-Remediation-Cycle: #265/cycle-1
Issue-Remediation-Cycle: #267/cycle-1
Issue-Remediation-Cycle: #269/cycle-1
Co-authored-by: Cursor <cursoragent@cursor.com>

* style: commit gate writer rewrites so make pr finishes once

* fix(c-009): AST cypher-lint scanner and value parameterization (F280-1, F280-2)

Audit findings F280-1/F280-2 on PR #280:

- tools/cypher_lint.py is now an AST scanner. Every f-string that builds
  Cypher (by text, by sink, or by compiler context) has each interpolation
  classified by syntactic role: quoted value and LIMIT/SKIP always fail;
  label, property, parameter-name and back-quoted positions must be
  validated; a bare fragment fails when it reads a raw spec value. No
  keyword precondition, multi-line f-strings analysed as one unit, and
  waivers are explicit, reasoned, and printed on every run.
- cypher_quoted_ident() is removed: it sanitized data as if it were a
  label. EnumMapGate mapping keys/values and GDS equipment type names now
  travel as $parameters via BaseGate._bind_param() / query_params.
- ExclusionGate sanitizes edge/node identifiers; _prop_ref/_param_ref
  validate identifiers; operators and composite logic pass through literal
  allow-lists aligned with the schema's validated set.
- GateCompiler validates query parameter names with sanitize_label() and
  casts numeric spec values; scoring builders validate dimension aliases
  and property/parameter names.
- sanitize_database_name() added for CREATE DATABASE quoting.

Tests cover both directions of the scanner (including the audit's
false-negative NOT EXISTS shape and false-positive module-constant MERGE),
non-identifier and injection-shaped enum values, and the live engine tree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dcSADmR2nDESm69Szd1fT

* fix(driver): make concurrent first-use callers await in-flight provisioning (F283-1)

ensure_database() claimed the name before awaiting CREATE DATABASE, so a
second request arriving mid-flight saw the name, returned True, and ran its
domain query against a database that did not exist yet. In-flight
provisioning is now a per-database asyncio.Task kept apart from the ensured
set; every concurrent caller awaits (shielded) the same task and receives
its result, exactly one CREATE is issued, a failed CREATE is retried on the
next call, and cancelling one waiter does not cancel the CREATE.

Tests prove one CREATE and no domain query before provisioning completes
under concurrency, shared outcome, retry after failure, and cancellation
isolation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dcSADmR2nDESm69Szd1fT

* ci: keep L9 analysis central; test: enforce docstring-only Protocol bodies (F284-1, F284-2)

- Drop the restored consumer-local .github/workflows/l9-analysis.yml.
  Current l9-ci-core owner law (consumer_copy_required=false) prohibits
  copied L9 workflows in consumers; Analyze (central Core) already passes
  on this repository, and the local duplicate only produced a
  startup_failure plus Scorecard/Sonar alerts.
- test_protocol_bodies.py now strips the optional leading docstring and
  fails on any remaining statement with its location, instead of only
  recognising pass / raise NotImplementedError / ellipsis. Negative fixtures
  cover return, assignment, arbitrary raise, calls, expressions and
  compound statements.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dcSADmR2nDESm69Szd1fT

* fix(ci): validated numeric casts, logger docstring examples, no bare awaits in tests

- Semgrep Policy Check (float-requires-try-except): numeric spec values now
  pass through engine.utils.security.cypher_number(), which does the float()
  conversion inside try/except and raises ValueError with the offending
  value; cypher-lint treats it as a validator alongside sanitize_label.
- Check Terminology Consistency (print( on changed files): docstring usage
  examples in hoprag/indexer, scoring/helpfulness, scoring/importance,
  traversal/multihop and traversal/pseudo_query use logger.info; the
  Protocol-body fixture uses len("x") as its call statement.
- github-code-quality "statement has no effect": the provisioning tests
  assert on the awaited task results instead of bare await statements.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dcSADmR2nDESm69Szd1fT

* feat(deps): detect a stale Gate_SDK lock, and enforce the pin in CI

CEG already declares the moving major channel correctly — pyproject
rev = "v1", requirements.txt @v1, poetry.lock reference = "v1" — and
none of that changes here. What was missing is the one failure a moving
tag makes possible and structural checks cannot see: Gate_SDK advances
`v1`, and this repository's lock silently stops matching it without a
single local file changing.

- scripts/validate_sdk_pin.py: adds --verify-tag. It resolves
  Quantum-L9/Gate_SDK@v1 at the canonical remote and requires
  poetry.lock's resolved_reference to equal it, failing closed when the
  remote cannot be resolved — an unverifiable lock has not been
  verified. check_text() and check_tree() are untouched, so the existing
  offline contract and its tests are unchanged; the new logic is three
  additive pure functions plus an argparse front door.
- tests/unit/test_validate_sdk_pin.py: covers the comparison directly —
  current lock, stale lock, unresolvable channel, lock with no
  resolved_reference. Pure logic, no network in the test suite.
- ci.yml: the validator was never actually wired into CI; it was only
  reachable through a unit test. Both modes now run in the
  merge-blocking validate job.

poetry.lock is NOT regenerated: resolved_reference is already
e9f829f982110be13752da8f18c7a9692e8ed908, which is what v1 resolves to
today, so there is nothing to refresh and no reason to churn the file.

Verified: ruff check, ruff format --check, 9 passed in
tests/unit/test_validate_sdk_pin.py, and both validator modes against
the live remote.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0153NHEJmFreprQ5tHLztSGq

* fix: address Codex and Copilot review on PR #285

- cypher-lint (Codex P1, Copilot): name facts are now lexically scoped — a
  sanitizer binding in one function no longer certifies a same-named
  variable in a sibling function; nested functions see enclosing scopes;
  a helper counts as validated only by its own return statements, never
  by returns inside a nested def. Scoping exposed five private helpers
  (resolution/similarity, feedback/drift_detector, feedback/signal_weights)
  that interpolated a label parameter relying on their callers to have
  sanitized it; each now validates the parameter itself.
- GraphDriver (Codex P2): execute_write provisions the domain database on
  first use and translates a missing-database error exactly like
  execute_query, via shared _provision_on_first_use /
  _translate_absent_database helpers.
- domain_extractor (Codex P2): writes domains/<domain-id>/spec.yaml, the
  only layout DomainPackLoader discovers.
- strictwhen (Copilot): declared by GateSpec, consumed by no compiler, so
  legal-discovery and research-agent are withheld behind
  unvalidated_domain_packs_enabled; the pack-shape test records strictwhen
  as a defect so the shrink-only guard still holds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dcSADmR2nDESm69Szd1fT

* docs(contracts): point the SDK install contract at the canonical channel

SHARED_MODELS.md is status: active and CLAUDE.md tells agents to load it
before touching engine/packet/. Under a heading reading "Installation
(pyproject.toml)" it prescribed:

    constellation-node-sdk = {git = "https://github.com/cryptoxdog/Gate_SDK.git"}

which is wrong twice over — the forbidden fork, and no ref at all, so it
floats on that fork's default branch. scripts/validate_sdk_pin.py fails
closed on both, meaning the doc instructed the next agent to write
something the repository's own gate rejects.

This is not the historical seam-audit evidence the release-identity
campaign deliberately leaves alone; it is a live instruction. Corrected
to the canonical repo on the v1 compatibility channel, with a note on
why the resolved object belongs in poetry.lock instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0153NHEJmFreprQ5tHLztSGq

* fix(security): refuse a Gate_SDK remote git would parse as an option

SonarCloud pythonsecurity:S8705 on the new --verify-tag code, and it is
a real finding, not a false positive. Passing argv as a list and never
invoking a shell stops *command* injection but not *argument* injection:
`git ls-remote --upload-pack=<cmd> <repo>` executes <cmd>, so a --remote
value beginning with `-` is an execution vector on its own.

Two independent guards, because either alone is a single point of
failure:
- safe_remote() rejects an empty remote or one starting with `-`, before
  it reaches git.
- --end-of-options is passed so git treats the remote as a positional
  even if the guard is ever loosened.

The rejection fails closed through the same path as any other
unresolvable channel, but names which of the two reasons it was rather
than reporting a generic resolution failure.

Tests cover both directions: a canonical https remote and a local
fixture path are accepted, and --upload-pack=..., -u, --exec=sh and ""
are refused. The Gate_SDK test drives it end to end through the CLI and
asserts the payload file was never created.

Introduced by my own --verify-tag commit on this branch; SonarCloud was
green on the previous head and red on mine. The same code was written
into all four validators, so all four carry this fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0153NHEJmFreprQ5tHLztSGq

* fix(security): the canonical remote is the contract, not a CLI option

My previous commit guarded the remote with a negative check and
--end-of-options. That is correct on the merits but SonarCloud still
reported pythonsecurity:S8705, and it was right to: a `startswith("-")`
rejection is not a sanitizer, so the argparse value still reached git
having only been filtered, not replaced. On Gate_SDK the report simply
moved from the resolver to the _git() helper.

The real problem was the flag existing at all. `--remote` let an
operator point a release-identity check at a repository that is not
Gate_SDK — which is precisely what this contract exists to prevent. So
the flag is gone:

- main() passes the CANONICAL_REMOTE module constant. No command-line
  argument reaches git.
- safe_remote() returns the constant on an equality match, so the value
  handed to the sink is provably not derived from any input. A
  non-canonical value is only accepted if it is an existing directory —
  the local fixture repositories the tests use — and a `-`-leading or
  empty value is still refused outright. --end-of-options stays as the
  third layer.
- The Gate_SDK tests that drove --verify-tag through the CLI now call
  validate(..., remote=...) in process, so the fixture path is a
  function parameter rather than a command-line argument.

This narrows what the tool can be pointed at, which is the behaviour the
release-identity contract wanted in the first place. Nothing about the
v1 channel, the lock comparison or the fail-closed semantics changes.

Verified in every repo: ruff, ruff format, the validator suites
(Gate_SDK 22, Gate 126, CEG 15, EIE 25 passed) and --verify-tag against
the live remote still reporting
e9f829f982110be13752da8f18c7a9692e8ed908.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0153NHEJmFreprQ5tHLztSGq

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude <noreply@anthropic.com>
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.

3 participants