Skip to content

CR-012/PR-012a: DAG-2026 foundation — single-source flag, DagSettings, ground-truth addendum - #260

Merged
harishquantamix merged 5 commits into
masterfrom
cr-012-pr-012a-public
Sep 16, 2026
Merged

harishquantamix merged 5 commits into
masterfrom
cr-012-pr-012a-public

Conversation

@quantamixsol

Copy link
Copy Markdown
Owner

Public port of the DAG-2026 foundation, cherry-picked after the private PR merged.

Private PR: quantamixsol/research-development-graqle#339 — APPROVED by the Research Team (rounds 1, 2+3, and the C1–C3 conditional approval), merged 2026-09-14 as f4a53b87.
Cherry-picked commits (feature commits only, never the merge commit): 93adcced, 5204add5, df543444, 8828d6e0, 5aa4ae78 → replayed here as be70039d, b143035e, a25a94ba, d6fb4229, ffe77e01.

What this is

The foundation layer for the Decision Assurance Gate programme (ADR-RT-004). It ships configuration plumbing and types only — no gate logic, no routing, no scoring.

  • graqle.assurance packageis_dag_enabled() (single-source flag reader; positive allowlist 1|true|yes|on, anything else OFF), DagSettings (one typed home for every DAG configuration symbol, GRAQLE_DAG_* prefix, frozen, unknown names rejected), ConfigurationError, load_dag_settings() (environment > private file at GRAQLE_DAG_SECRETS_PATH > safe default; cached only on success), config_version() (deterministic fingerprint; private values never in clear), config_provenance(), validate_flag_consistency().
  • GraqleConfig.assuranceenabled is derived from the environment flag and is read-only. Setting assurance.enabled in graqle.yaml raises ConfigurationError before environment interpolation.
  • .env.example at the repo root — every DAG variable NAME with placeholders. No tuning values.
  • docs/dag/ground-truth-addendum.md — the charter-correction record, plus an operator section covering CSPRNG salt generation and rotation, the Kubernetes defaultMode: 0400 requirement, and the Windows residual.

Three statements the Research Team asked for explicitly

  1. The flag is off by default. GRAQLE_DAG_ENABLED defaults to unset, which resolves to OFF.
  2. No behaviour change — 0.83.0 parity. With the flag off, nothing in this package alters SDK behaviour. The only always-on change is an additive, derived assurance section on GraqleConfig.
  3. GovernanceMiddleware.check() is untouched. Verified by diff guard: graqle/core/governance.py, graqle/governance/*, graqle/intelligence/governance/drace.py and graqle/core/rbac.py are all byte-identical to master on this branch.

Verification on this branch

ruff check graqle/assurance tests/test_assurance tests/test_docs   → All checks passed
pytest tests/test_assurance tests/test_docs tests/test_config \
       tests/test_public_api tests/test_packaging -q                → 395 passed, 3 skipped

Rebased onto current master after CR-README-02 (#259) landed, so the diff is exactly the nine PR-012a paths and nothing else. CHANGELOG.md is deliberately unchanged: master already carries the ## Unreleased — 0.84.0 (DAG-2026 CR-012 foundation) block, and the released ## 0.84.0 section must not be disturbed.

Version note

This does not ship in a new version. Per the Research-Team ruling, the DAG foundation is released only once the gate vocabulary (PR-012b: GateOutcome, the reason-code registry, GateVerdict, trace schema v3) lands alongside it. The published 0.84.0 artifact does not contain this code, and the CHANGELOG entry stays under Unreleased until a version carries it.

🤖 Generated with Claude Code

quantamixsol and others added 5 commits September 15, 2026 08:33
…ound-truth addendum

DAG-2026 foundation (ADR-RT-004, CR-012 s4.5/s5.1). Adds graqle.assurance with is_dag_enabled() (positive allowlist, default OFF), DagSettings (every DAG symbol typed, GRAQLE_DAG_ prefix, frozen, 0 rejected for gate thresholds and cap, required-when-enabled fail-closed), load_dag_settings() (env > private file > safe default, cached only on success, drift lock on unknown GRAQLE_DAG_* names), config_version() (joint HMAC commitment, secret values never in clear), validate_flag_consistency() wired into GraqleConfig.from_yaml(). GraqleConfig gains a read-only assurance.enabled derived from the env flag; assurance.enabled in graqle.yaml is rejected before env interpolation. Adds .env.example (placeholders only) and docs/dag/ground-truth-addendum.md with line-anchor verification notes. Flag off => GovernanceMiddleware.check() untouched. 84 new tests; tests/test_config unchanged (217 pass). Deviations from the CR and the D1 P0 reproduction are in the PR body and issue #338.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 93adcced88dcc332e988535e32e1571c0e214a4e)
…C binding, M-3 number-free hints, from_yaml contract)

graq_reason sentinel pass 1 (81%) REQUEST CHANGES: B-1 cache critical section now under an RLock with double-checked freshness; M-1 secrets digest message bound to the non-secret payload under a domain label (key = secret values, never serialised); M-3 ValidationError conversion maps pydantic error types to number-free operator hints and names the env var; B-2 documented as the intended fail-closed startup boundary in from_yaml's Raises (policy question stays with issue #338 N5). Refuted: m-4 (drift scan already case-insensitive). M-2 (computed_field vs property) left for the #338 N3 ruling — two sentinel passes disagreed. 301 tests pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 5204add5e30c770085f9adff33cc35ab06b0e372)
…k-is-absent, M2 cache key, M3 path/file safety, N1/N3/N4 (rulings N2/N3/N4; PR-339 round 1)

B1: new DagSettings.config_salt (GRAQLE_DAG_CONFIG_SALT, REQUIRED_WHEN_ENABLED, >=32 bytes, SecretStr, never logged/serialised, excluded from the payload); config_version HMAC key = salt, message = label | canon(secret values) | canon(non-secret payload); keying tag deployment_salt_v1 / joint_canonical_v1 in config_provenance (ruling N2). M1: '', whitespace and None are absent for every REQUIRED_WHEN_ENABLED field. M2: cache token = (flag snapshot, sha256 of all GRAQLE_DAG_* env values, resolved secrets path, mtime_ns, size); flag snapshotted once per load; reset clears the token under the lock. M3: path-typed fields excluded from the fingerprint; secrets file resolve(), regular-file check, POSIX 0o077 refusal with chmod 600 message, Windows WARNING. N1: core.rbac ImportError -> ConfigurationError. N3: tautology documented. N4: DEBUG log of exception type before from None. Tests: +22 (salt/blank/cache/path/mode/rbac/debug); 393 pass across tests/test_assurance tests/test_docs tests/test_config tests/test_public_api tests/test_packaging.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit df5434443e0babb133999eb29aa8c00afed6b960)
…descriptor (O_NOFOLLOW + fstat), symlink test

Post-implementation sentinel pass 1 on df543444 (graq_reason tool 0.685 / synth 81%) flagged the resolve->stat->open sequence as a TOCTOU/symlink race. Fix: _open_secrets_file opens with O_RDONLY|O_NOFOLLOW|O_CLOEXEC on POSIX and runs the regular-file and 0o077 mode checks on fstat() of the open descriptor before reading from it; ELOOP/IsADirectory -> ConfigurationError naming the path; Windows keeps the best-effort path + WARNING. Refuted after verification (not changed): MAJ-1 'salt rotation invisible to the cache token' (the env fingerprint covers GRAQLE_DAG_CONFIG_SALT; test_b1_identical_secrets_different_salts_differ reloads without force), MAJ-2 'keying tag is an oracle' (with the salt required when enabled the tag is a function of the public flag state; the tag is required by ruling N2). 393 pass, 7 platform skips.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 8828d6e067d661ce84b29464dc2d6bc311f6100d)
…t_ino in cache token, operator docs)

Research-Team rounds 2+3 APPROVED conditional on C1-C3 (pull/339#issuecomment-5656126399). C1: the value-keyed HMAC fallback is removed - a MAC keyed by the data it authenticates must not exist as a precedent even when unreachable. With a salt the digest is HMAC-SHA256 under GRAQLE_DAG_CONFIG_SALT (keying=deployment_salt_v1); without one it is an explicitly unkeyed sha256 over label | canon(secrets) | canon(public) (keying=unkeyed_checksum_v1). KEYING_JOINT_CANONICAL deleted; CR-018 note recorded that anchoring must refuse any keying other than deployment_salt_v1. C2: st_ino added to the cache token - an atomic rename-replacement can preserve mtime_ns and size. C3: .env.example requires a CSPRNG-generated salt (openssl rand -base64 48, never a passphrase); new 'Operating the DAG flag' section in docs/dag/ground-truth-addendum.md covers salt generation and rotation, the Kubernetes 0644 refusal and its defaultMode 0400 remedy, and the Windows residual. +4 tests (unkeyed digest recomputed and shown not to be the old MAC, source grep against the precedent, inode-change reload with mtime_ns and size held equal). 395 passed, 7 skipped; ruff clean; governance/drace/rbac/config-settings diff empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 5aa4ae78e8790c190e11114e45ff9178af52c12b)
@github-actions

Copy link
Copy Markdown

🛡️ GraQle PR Guardian

💥 Blast Radius: 9 modules affected

Module Files Changed Risk Level Impact Radius
.env.example 1 🟡 T2 1
docs 1 🟡 T2 1
graqle 3 🟠 T3 3
tests 4 🟡 T2 4

Total blast radius: 9


🏛️ Governance Verdict

🚫 FAIL

  • T3: 1 file(s) require explicit approval.

🔍 SHACL Violations

No SHACL violations detected.


🔐 Approval Requirements

This PR requires approval from: T3

  • A registered Tech Lead or Governance Admin must approve.

Approval requirement NOT yet satisfied.


Metric Value
Blast Radius 9
Files Analyzed 9
Blocked 1
SHACL Violations 0
Verdict FAIL

🔬 Powered by GraQle PR Guardian v0.1.0 · Scan completed 2026-09-15T06:35:27.775398+00:00

@harishquantamix
harishquantamix merged commit fcff174 into master Sep 16, 2026
15 of 20 checks passed
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.

2 participants