Skip to content

feat: add generate-node scaffolding script [OMN-7585] - #2

Merged
jonahgabriel merged 1 commit into
mainfrom
jonah/omn-7585-generate-node
Apr 5, 2026
Merged

jonahgabriel merged 1 commit into
mainfrom
jonah/omn-7585-generate-node

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Apr 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds scripts/generate_node.py — a Python scaffolding script that generates a complete ONEX node package using string templates (no Jinja2 dependency)
  • Generates: contract.yaml, handler stub, metadata.yaml, golden chain test, and __init__.py files
  • Supports --name <snake_case> and --type compute|effect|reducer|orchestrator with correct purity/side_effect_class per type

Test plan

  • Generated a compute node (test_scaffold), golden chain test passed (2/2)
  • Generated an effect node (test_effect), verified purity: impure and side_effect_class: write
  • All 22 existing tests still pass after cleanup
  • CI green

Summary by CodeRabbit

  • New Features
    • Added a scaffolding tool to create and initialize new ONEX node packages
    • Supports four configurable node types: compute, effect, reducer, and orchestrator
    • Automatically generates configuration files, handler implementations, tests, and complete package structure with a single command

Python script using string templates (no Jinja2) that generates a
complete ONEX node package: contract.yaml, handler stub, metadata.yaml,
golden chain test, and __init__.py files.

Supports --name and --type (compute|effect|reducer|orchestrator) with
correct purity/side_effect_class per type.
@linear

linear Bot commented Apr 5, 2026

Copy link
Copy Markdown

OMN-7585

@coderabbitai

coderabbitai Bot commented Apr 5, 2026 •

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Lite

Run ID: fff3dac4-6bac-46fd-873f-ccadd7bce350

📥 Commits

Reviewing files that changed from the base of the PR and between 060a7d8 and 686d9a9.

📒 Files selected for processing (1)
  • scripts/generate_node.py

📝 Walkthrough

Walkthrough

Introduced scripts/generate_node.py, a CLI tool that scaffolds complete ONEX node packages by generating contract.yaml, metadata.yaml, handler modules, test files, and package initializers for specified node types.

Changes

Cohort / File(s) Summary
Node Package Scaffolding
scripts/generate_node.py
Added new Python script implementing a CLI tool for generating ONEX node packages. Includes support for four node types (compute, effect, reducer, orchestrator), name conversion utilities (snake_case to PascalCase, kebab-case handling), template generation for contract.yaml with routing metadata, metadata.yaml with entry point and capability configuration, handler modules with dataclass request/result types and stub Node implementation, test scaffolding with in-memory event bus integration, and package initializers. Implements input validation, directory existence checks, and file I/O with directory creation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 A rabbit scripts node generators neat,
Scaffolding packages, templates complete,
With handlers and contracts in place,
ONEX nodes spring forth at a pace,
New packages grow with graceful beat! ✨


Comment @coderabbitai help to get the list of available commands and usage tips.

@jonahgabriel
jonahgabriel merged commit f4253b7 into main Apr 5, 2026
1 check was pending
jonahgabriel added a commit that referenced this pull request Apr 21, 2026
…, fix deps

New nodes (picks #2 and #7 from prioritized list):

- node_two_strike_arbiter (effect): Monitors consecutive fix-attempt failures.
  After 2 strikes, writes a diagnosis document, moves Linear ticket to Blocked,
  and files a friction event. Implements the two-strike protocol from GEMINI.md.
  Subscribes: onex.evt.omnimarket.fix-attempt-failed.v1
  Publishes: onex.evt.omnimarket.two-strike-arbiter.v1

- node_audit_trail_compactor (compute): Reads friction + dispatch logs,
  computes failure modes, recurring tickets, stall heatmap. Compact output
  for overseer-verify and session-post-mortem consumption.
  Subscribes: onex.cmd.omnimarket.audit-trail-compact.v1
  Publishes: onex.evt.omnimarket.audit-trail-compacted.v1

Dependency fix (same as PR #372):
- Replace path sources with git sources for portable resolution
- Add git sources for omnibase-spi, omninode-memory (PyPI stale)
- Add omnibase-spi as explicit direct dep for git source override

Tests: 16 new golden chain tests (7 arbiter + 9 compactor), all pass.

Assisted-by: GLM-5.1 (z.ai) via Crush <crush@charm.land>
jonahgabriel added a commit that referenced this pull request Apr 22, 2026
…, fix deps

New nodes (picks #2 and #7 from prioritized list):

- node_two_strike_arbiter (effect): Monitors consecutive fix-attempt failures.
  After 2 strikes, writes a diagnosis document, moves Linear ticket to Blocked,
  and files a friction event. Implements the two-strike protocol from GEMINI.md.
  Subscribes: onex.evt.omnimarket.fix-attempt-failed.v1
  Publishes: onex.evt.omnimarket.two-strike-arbiter.v1

- node_audit_trail_compactor (compute): Reads friction + dispatch logs,
  computes failure modes, recurring tickets, stall heatmap. Compact output
  for overseer-verify and session-post-mortem consumption.
  Subscribes: onex.cmd.omnimarket.audit-trail-compact.v1
  Publishes: onex.evt.omnimarket.audit-trail-compacted.v1

Dependency fix (same as PR #372):
- Replace path sources with git sources for portable resolution
- Add git sources for omnibase-spi, omninode-memory (PyPI stale)
- Add omnibase-spi as explicit direct dep for git source override

Tests: 16 new golden chain tests (7 arbiter + 9 compactor), all pass.

Assisted-by: GLM-5.1 (z.ai) via Crush <crush@charm.land>
github-actions Bot pushed a commit to andywu42/omnimarket that referenced this pull request Apr 23, 2026
…9403] (OmniNode-ai#368)

* feat(linear-triage): replace gh subprocess with GitHub REST API [OMN-9403]

- Add GitHubClientProtocol + GitHubHttpClient using urllib (zero external deps)
- Reads GH_PAT from env (fail-fast, no silent fallback)
- Only PR-check tickets in In Progress/In Review (43 vs 682)
- Only check epic completion for active root tickets (25 vs 1663)
- Rate-limit awareness: auto-sleeps on x-ratelimit-remaining exhaustion
- Error handling for Linear list_children 400s on non-epic tickets
- Updated golden chain tests to use DI stubs (GitHubClientProtocol)
  instead of monkeypatching module-level functions
- All 8 golden chain tests pass
- End-to-end verified via: onex node node_linear_triage --input input.json

* fix: sort imports for ruff I001 [OMN-9403]

* feat(nodes): add node_two_strike_arbiter + node_audit_trail_compactor, fix deps

New nodes (picks OmniNode-ai#2 and OmniNode-ai#7 from prioritized list):

- node_two_strike_arbiter (effect): Monitors consecutive fix-attempt failures.
  After 2 strikes, writes a diagnosis document, moves Linear ticket to Blocked,
  and files a friction event. Implements the two-strike protocol from GEMINI.md.
  Subscribes: onex.evt.omnimarket.fix-attempt-failed.v1
  Publishes: onex.evt.omnimarket.two-strike-arbiter.v1

- node_audit_trail_compactor (compute): Reads friction + dispatch logs,
  computes failure modes, recurring tickets, stall heatmap. Compact output
  for overseer-verify and session-post-mortem consumption.
  Subscribes: onex.cmd.omnimarket.audit-trail-compact.v1
  Publishes: onex.evt.omnimarket.audit-trail-compacted.v1

Dependency fix (same as PR OmniNode-ai#372):
- Replace path sources with git sources for portable resolution
- Add git sources for omnibase-spi, omninode-memory (PyPI stale)
- Add omnibase-spi as explicit direct dep for git source override

Tests: 16 new golden chain tests (7 arbiter + 9 compactor), all pass.

Assisted-by: GLM-5.1 (z.ai) via Crush <crush@charm.land>

* fix: resolve 9 CodeRabbit review threads on PR OmniNode-ai#368

- handler_audit_trail_compactor: compare datetimes not ISO strings (thread 5);
  add _parse_recorded_at() helper; sort last_failure by timestamp not list order
  (thread 6)
- handler_linear_triage: narrow list_children except to only suppress known
  non-epic errors, re-raise auth/transport faults (thread 4); re-raise
  _get() failures in search_prs/search_prs_in_repo/list_prs_by_head instead
  of collapsing to [] (thread 7)
- handler_two_strike_arbiter: capture move_to_blocked() return value; report
  strongest successful side-effect action (TICKET_BLOCKED / FRICTION_FILED /
  DIAGNOSIS_WRITTEN) instead of always SECOND_STRIKE (thread 8)
- test_golden_chain_audit_trail_compactor: make timestamps relative to now()
  so suite does not break after 7-day lookback window expires (thread 9)

Threads 1/2/3 verified already addressed in current code.
jonahgabriel added a commit that referenced this pull request Apr 30, 2026
CR Major #1 (durable_evidence_gate.py:~141-159):
extract_cited_merge_commits accepted any string sha and let
ModelCitedMergeCommit (min_length=7) raise ValidationError on
malformed short SHAs — contract violation vs the docstring's
"malformed citations are skipped" promise. Added _SHA_RE guard
([0-9a-fA-F]{7,40}) before parse_pr_url; malformed SHAs are now
silently skipped. Regression test:
test_extract_skips_malformed_short_sha.

CR Major #2 (same file, dedupe + cross-set comparison):
Citation dedupe and CONTRACT_ON_OCC_MAIN comparison were keyed on
raw pr_url, so /pull/123 and /pull/123/files for the same PR were
treated as distinct citations — caused double gh_pr_view() calls
AND false CONTRACT_ON_OCC_MAIN hard-fails when local and OCC main
spelled the same PR differently. Switched both keys to the
normalized identity (repo, pr_number, sha). Regression tests:
test_url_variants_dedupe_to_same_citation and
test_url_variants_across_local_and_main_do_not_hard_fail.

deploy-gate root cause:
Action matcher src/*/nodes/**/*.py flagged the pure-logic gate
service as a runtime path. Added dod-005 to contracts/OMN-10407.yaml
documenting the deploy posture honestly: this slice is pure logic
+ Protocol probes, no container/topic touched, and concrete probe
wiring + FSM integration ship in a follow-up ticket carrying its
own deploy evidence. check_value contains "deploy" so the gate
recognizes intent. NO skip token used.

Verification:
- 70/70 node_dod_verify unit tests green (was 67, +3 new).
- Full uv run pytest tests/ -m "not kafka and not integration":
  2786 passed / 0 failed (was 2783).
- uv run ruff format/check, uv run mypy --strict on
  node_dod_verify/, all clean.
- OMNIBASE_INFRA_PATH=... pre-commit run --all-files: all hooks
  pass.
- Local replay of validate_pr_deploy_required.py against the
  three changed files now returns DEPLOY GATE PASSED.

CR fingerprints (CodeRabbit auto-resolves on resolution):
phantom:medusa:ocelot:97a9ca79-253e-49f4-bb67-27581b204d27
4e71b3a2
andywu42 pushed a commit to andywu42/omnimarket that referenced this pull request May 12, 2026
…mniNode-ai#467)

* feat(OMN-10407): durable-evidence gate before Linear Done transition

Adds a pure-logic DurableEvidenceGate service in node_dod_verify that
refuses Linear Done when the durable evidence trail is local-only.

OMN-9855 incident shape (2026-04-30):
- Worker probed implementation already on omnibase_core/main (PR OmniNode-ai#949)
- Generated DoD receipt LOCALLY at evidence/OMN-9855/dod_report.json,
  never committed
- Updated Linear dod_evidence text to point at PR OmniNode-ai#949
- onex_change_control/main still had stale contract citing superseded OmniNode-ai#926
- Linear flipped Done; durable trail unverifiable from origin alone

The gate enforces three checks before any Linear Done transition:

1. RECEIPT_TRACKED — evidence/<TICKET>/dod_report.json must be tracked
   on onex_change_control/main (not just present on disk).
2. CONTRACT_CITES_MERGE_COMMIT — every cited pr_url has gh-state MERGED
   and mergeCommit.oid matches the cited commit_sha. Closed/superseded
   PRs HARD FAIL.
3. CONTRACT_ON_OCC_MAIN — the contract version on OCC main contains the
   real merge-commit citation. Stale main HARD FAIL with explicit "open
   an OCC PR first" remediation hint.

Failure raises DurableEvidenceGateError carrying the structured
ModelDurableEvidenceGateResult; the first failed check supplies the
remediation hint.

Architecture:
- Pure-logic gate + Protocol-typed probes (GitTrackedProbe,
  GhPrViewProbe, ContractOnRefLoader). Tests inject deterministic stubs.
- New schema module model_durable_evidence_gate.py is pure (no I/O,
  no env, no time) per onex_change_control D-008 schema purity rules.
- Production probe wiring (subprocess-backed git ls-tree / gh pr view /
  yaml load on git ref) is intentionally out of scope for this slice;
  follow-up ticket will wire the gate into the FSM phase ordering.

DoD evidence:
- 16 unit tests cover untracked receipt, superseded PR, wrong SHA,
  stale main, missing-on-main, structured error raise, citation
  extraction (top-level + nested + dedup + malformed), URL parser.
- All 2783 non-kafka non-integration omnimarket tests pass.
- mypy --strict clean on src/omnimarket/nodes/node_dod_verify/.
- ruff format + check clean; pre-commit hooks all green.

* fix(OMN-10407): address CR findings + deploy-gate (PR OmniNode-ai#467)

CR Major OmniNode-ai#1 (durable_evidence_gate.py:~141-159):
extract_cited_merge_commits accepted any string sha and let
ModelCitedMergeCommit (min_length=7) raise ValidationError on
malformed short SHAs — contract violation vs the docstring's
"malformed citations are skipped" promise. Added _SHA_RE guard
([0-9a-fA-F]{7,40}) before parse_pr_url; malformed SHAs are now
silently skipped. Regression test:
test_extract_skips_malformed_short_sha.

CR Major OmniNode-ai#2 (same file, dedupe + cross-set comparison):
Citation dedupe and CONTRACT_ON_OCC_MAIN comparison were keyed on
raw pr_url, so OmniNode-ai/pull/123 and OmniNode-ai/pull/123/files for the same PR were
treated as distinct citations — caused double gh_pr_view() calls
AND false CONTRACT_ON_OCC_MAIN hard-fails when local and OCC main
spelled the same PR differently. Switched both keys to the
normalized identity (repo, pr_number, sha). Regression tests:
test_url_variants_dedupe_to_same_citation and
test_url_variants_across_local_and_main_do_not_hard_fail.

deploy-gate root cause:
Action matcher src/*/nodes/**/*.py flagged the pure-logic gate
service as a runtime path. Added dod-005 to contracts/OMN-10407.yaml
documenting the deploy posture honestly: this slice is pure logic
+ Protocol probes, no container/topic touched, and concrete probe
wiring + FSM integration ship in a follow-up ticket carrying its
own deploy evidence. check_value contains "deploy" so the gate
recognizes intent. NO skip token used.

Verification:
- 70/70 node_dod_verify unit tests green (was 67, +3 new).
- Full uv run pytest tests/ -m "not kafka and not integration":
  2786 passed / 0 failed (was 2783).
- uv run ruff format/check, uv run mypy --strict on
  node_dod_verify/, all clean.
- OMNIBASE_INFRA_PATH=... pre-commit run --all-files: all hooks
  pass.
- Local replay of validate_pr_deploy_required.py against the
  three changed files now returns DEPLOY GATE PASSED.

CR fingerprints (CodeRabbit auto-resolves on resolution):
phantom:medusa:ocelot:97a9ca79-253e-49f4-bb67-27581b204d27
4e71b3a2
andywu42 pushed a commit to andywu42/omnimarket that referenced this pull request Jul 6, 2026
…s (Systemic OmniNode-ai#2) (OmniNode-ai#1519)

Eight nodes crashed or emitted vacuous "clean"/epoch-0 data when run over the
canonical in-memory/local event bus because they required a Kafka/remote adapter
instead of defaulting to a local impl (remote as override). DI-resolve a local
default per node and refuse to report a vacuous false-green:

- node_observability_sink_effect: InMemoryObservabilitySink default (Kafka/PG override)
- node_pipeline_audit_orchestrator: LocalTicketStore default (Linear override)
- node_verification_sweep_orchestrator: LocalReceiptWriter default (OCC override)
- node_tech_debt_sweep_orchestrator: LocalLinearAdapter default (Linear override)
- node_dep_cascade_dedup_orchestrator: LocalGithubAdapter default (GitHub override)
- node_ticketing_insights_compute: fail loud instead of fabricating epoch-0 (1969) dates
- node_runtime_sweep: 0 entities checked -> status=no_input (was vacuous clean)
- node_dashboard_sweep: 0 pages examined -> status=no_targets (was vacuous clean)

Follows node_recall_compute's honest-degradation pattern. Handlers stay
stateless/contract-driven; no new topics, endpoints, or runtime mutation.
jonahgabriel added a commit that referenced this pull request Jul 7, 2026
…fix (local-first, offline) (#1626)

* feat(OMN-13998): 2x2 SWE-discriminator harness + truncation-confound fix

Promotes the OMN-13988 de-risk spike into a durable, tested harness and fixes
the capability-vs-plumbing confound (blocker #2). Local-first, offline over
captured artifacts (proof_class = offline; NOT a live runtime loop).

New package omnimarket.delegation.swe_discriminator (extends graded_ladder):
- 2x2 arm runner (monolith/decomposed x frontier/cost_routed), decomposer +
  per-slice worker + concat integration, balanced-bracket slice parser
- offline blind deterministic floor grader (verifier != runner)
- classify.py: detect_truncation + classify_run separate PASS/FAIL_WRONG
  (capability) from TRUNCATED/BLOCKED (plumbing/infra, excluded) so a token-cap
  truncation cannot deflate the hard-tier numbers (OMN-13335 hazard)
- model_client: finish_reason capture, reasoning-aware budget (SWE_MAX_TOKENS,
  default 16384), 429 retry/backoff, env-overridable frontier; no hardcoded IPs
- run_smoke: 2-phase RUN/GRADE orchestrator, pass^k repeats + PassKCell aggregate

Evidence (docs/evidence/2026-07-05-swe-discriminator-smoke/):
- grader calibration (selftest): real merged solutions PASS floor, pre-fix FAIL
- 13 unit tests incl truncation detector proven on the EXACT live L3 repro
- live pass^3 on L1 local arms (3/3); genuine decomposition (parsed slice + tax)
- canonical 4-arm run: L1 local pass, L3 local correctly TRUNCATED, frontier BLOCKED

Full 2x2 headline run remains gated on frontier reachability (blocker #1) and a
larger hard-task budget/reasoning control (follow-ups). mypy --strict + ruff clean.

* fix(OMN-13998): resolve tier endpoints from ladder_rungs config (url-authority gate)

Removes the literal frontier URL const and the SWE_FRONTIER_URL env read that
tripped the url-authority gate (2 violations). Endpoints now resolve from the
committed graded_ladder ladder_rungs.yaml routing config (the same integration
catalog the ladder recorder uses); rung selection is by id via SWE_FRONTIER_RUNG
/ SWE_COST_RUNG, keys/endpoints named by the rung, never a hardcoded URL.
Verified: validator_url_authority reports 0 swe_discriminator violations; mypy
--strict + ruff clean; 13 unit tests + grader selftest green; resolve_tier
resolves frontier->glm-5.2 and cost_routed->local from config.

* fix(OMN-13998): pass SWE discriminator runtime config explicitly

* fix(OMN-13998): harden SWE smoke artifacts and parsing

* ci(OMN-13998): refresh stuck checks

* ci(OMN-13998): harden reviewer uv sync

* ci(OMN-13998): extend hostile reviewer timeout

* ci(OMN-13998): retrigger stuck hostile reviewer

* fix(OMN-13998): handle malformed chat choices

* test(OMN-13998): match urlopen timeout keyword

* ci(OMN-13998): refresh cancelled check set

* ci(OMN-13998): retrigger stale queued validators

* ci(OMN-13998): refresh cancelled hostile reviewer

* test(OMN-13998): accept ROI overlay in delegation ladder shim
jonahgabriel added a commit that referenced this pull request Jul 16, 2026
…s pre-commit hooks (DRY) + fail-loud meta-gate

Applies the WS7 CI<->pre-commit gate-parity pattern (plan
docs/plans/2026-07-15-ci-precommit-gate-parity-plan.md §4; canary
omniclaude#1904 / OMN-14655, MERGED) to omnimarket — fan-out #2 only.

What this does
- Wire two STATIC arch/registry CI checks as `repo: local` pre-commit hooks
  invoking the EXACT ci.yml entrypoint (DRY, no re-impl, plan §2/§5):
    * arch-node-metadata-dependency-scope
        entry `uv run python scripts/ci/check_node_metadata_dependencies.py`
        (byte-identical to ci.yml:200)
    * arch-unimported-handler-check
        entry `uv run python scripts/ci/check_unimported_handlers.py`
        (byte-identical to ci.yml:259)
  Per-check STATIC classification receipt (plan §3a/D3) in the config comment:
  both are pure AST/stdlib scans, NO sibling checkout, NO env vars, NO network,
  NO runtime execution.
- Fix DRIFT-5 false-green: `default_install_hook_types: [pre-commit]` ->
  `[pre-commit, pre-push, commit-msg]`, so the strict-mypy (stages:[pre-push])
  and reject-deploy-gate-skip-token-commit-msg (stages:[commit-msg]) hooks —
  both required-CI mirrors that `pre-commit install` NEVER installed before —
  now actually install and enforce.
- Add the fail-loud meta-gate + pin-parity ratchet (plan §3d.7/§3d.8), ported
  from the canary: scripts/validation/validate_precommit_fail_loud.py +
  validate_precommit_pin_parity.py, the two `repo: local` hooks, and the CI
  mirror .github/workflows/precommit-fail-loud-gate.yml. pin-parity PIN_PAIRS =
  no-noncanonical-lifecycle-classes (pre-commit rev 63635097… already == the
  ci.yml:1498 `omnibase-core @ git+…@<sha>` pin).

Net-negative-surface (plan §5/D11): converts two never-installed hooks
(strict-mypy, commit-msg skip-token) into installed, enforcing hooks, and the
fail-loud meta-gate retires the exit-0-on-missing false-green CLASS (mechanism,
not rule — CLAUDE.md §5) rather than adding advisory surface.

Scope guard (canary): omnimarket ONLY, do NOT fan out. Excluded and tracked
separately: canonical handler-shape GROWTH ratchet (OMN-14563);
runtime/compliance/aislop sweeps + contract-compliance (sibling-checkout /
PR-diff, CI-only or later); reject-node-topics.py inline bash (needs §2 D2
entrypoint extraction); run_quality_gate_calibration.py (imports+executes
handler code = RUNTIME); topic-drift/enum-drift (dep classification pending).

dod_evidence (OMN-14666, proof gate plan §4; run from worktree off origin/dev):
- BASELINE GREEN: both arch checks pass on clean tree via the exact CI command.
- SEEDED-BREAK REJECTED (parity = same script -> same message CI emits):
  unimported-handler (unwired Handler class) -> exit 1; metadata-dep (undeclared
  `import qdrant_client`) -> `missing dependencies for imports: qdrant-client`,
  exit 1; pin-parity (flipped no-noncanonical rev) -> FAIL on divergence, exit 1.
  Each reverted; tree clean before commit.
- META-GATE GREEN on final config via CI invocation (uv run --no-project
  --with pyyaml python3 …): fail-loud + pin-parity both OK.
- BUDGET: 4 new hooks measured via pre-commit run = 1.22/1.60/0.23/0.22s
  (~3.3s combined), under the <15s pre-commit budget (plan §4).
- The only pre-commit red is the PRE-EXISTING topic-naming-lint hard-exit-2 when
  the ../omnibase_infra sibling is unresolved — the §3d.2 env-parity prerequisite,
  NOT introduced here; passes with OMNIBASE_INFRA_PATH set. Out of scope.

Related: OMN-14655 (parent/canary), OMN-14643 (epic WS7), OMN-14563 (excluded).
jonahgabriel added a commit that referenced this pull request Jul 16, 2026
…s pre-commit hooks (DRY) + fail-loud meta-gate (#1783)

Applies the WS7 CI<->pre-commit gate-parity pattern (plan
docs/plans/2026-07-15-ci-precommit-gate-parity-plan.md §4; canary
omniclaude#1904 / OMN-14655, MERGED) to omnimarket — fan-out #2 only.

What this does
- Wire two STATIC arch/registry CI checks as `repo: local` pre-commit hooks
  invoking the EXACT ci.yml entrypoint (DRY, no re-impl, plan §2/§5):
    * arch-node-metadata-dependency-scope
        entry `uv run python scripts/ci/check_node_metadata_dependencies.py`
        (byte-identical to ci.yml:200)
    * arch-unimported-handler-check
        entry `uv run python scripts/ci/check_unimported_handlers.py`
        (byte-identical to ci.yml:259)
  Per-check STATIC classification receipt (plan §3a/D3) in the config comment:
  both are pure AST/stdlib scans, NO sibling checkout, NO env vars, NO network,
  NO runtime execution.
- Fix DRIFT-5 false-green: `default_install_hook_types: [pre-commit]` ->
  `[pre-commit, pre-push, commit-msg]`, so the strict-mypy (stages:[pre-push])
  and reject-deploy-gate-skip-token-commit-msg (stages:[commit-msg]) hooks —
  both required-CI mirrors that `pre-commit install` NEVER installed before —
  now actually install and enforce.
- Add the fail-loud meta-gate + pin-parity ratchet (plan §3d.7/§3d.8), ported
  from the canary: scripts/validation/validate_precommit_fail_loud.py +
  validate_precommit_pin_parity.py, the two `repo: local` hooks, and the CI
  mirror .github/workflows/precommit-fail-loud-gate.yml. pin-parity PIN_PAIRS =
  no-noncanonical-lifecycle-classes (pre-commit rev 63635097… already == the
  ci.yml:1498 `omnibase-core @ git+…@<sha>` pin).

Net-negative-surface (plan §5/D11): converts two never-installed hooks
(strict-mypy, commit-msg skip-token) into installed, enforcing hooks, and the
fail-loud meta-gate retires the exit-0-on-missing false-green CLASS (mechanism,
not rule — CLAUDE.md §5) rather than adding advisory surface.

Scope guard (canary): omnimarket ONLY, do NOT fan out. Excluded and tracked
separately: canonical handler-shape GROWTH ratchet (OMN-14563);
runtime/compliance/aislop sweeps + contract-compliance (sibling-checkout /
PR-diff, CI-only or later); reject-node-topics.py inline bash (needs §2 D2
entrypoint extraction); run_quality_gate_calibration.py (imports+executes
handler code = RUNTIME); topic-drift/enum-drift (dep classification pending).

dod_evidence (OMN-14666, proof gate plan §4; run from worktree off origin/dev):
- BASELINE GREEN: both arch checks pass on clean tree via the exact CI command.
- SEEDED-BREAK REJECTED (parity = same script -> same message CI emits):
  unimported-handler (unwired Handler class) -> exit 1; metadata-dep (undeclared
  `import qdrant_client`) -> `missing dependencies for imports: qdrant-client`,
  exit 1; pin-parity (flipped no-noncanonical rev) -> FAIL on divergence, exit 1.
  Each reverted; tree clean before commit.
- META-GATE GREEN on final config via CI invocation (uv run --no-project
  --with pyyaml python3 …): fail-loud + pin-parity both OK.
- BUDGET: 4 new hooks measured via pre-commit run = 1.22/1.60/0.23/0.22s
  (~3.3s combined), under the <15s pre-commit budget (plan §4).
- The only pre-commit red is the PRE-EXISTING topic-naming-lint hard-exit-2 when
  the ../omnibase_infra sibling is unresolved — the §3d.2 env-parity prerequisite,
  NOT introduced here; passes with OMNIBASE_INFRA_PATH set. Out of scope.

Related: OMN-14655 (parent/canary), OMN-14643 (epic WS7), OMN-14563 (excluded).
jonahgabriel added a commit that referenced this pull request Jul 16, 2026
The WS7 #2 (pre-lesson) fail-loud gate still carried all three false-green
vectors the later fan-out repos designed out:

  1. runs-on routed only public-fork PRs to hosted, leaving trusted internal
     PRs on the self-hosted omnibase-ci fleet (saturated/absent fleet =
     queued/cancelled required check = false-green window).
  2. needs: occ-preflight — the exact skip-then-vacuous-green vector the
     OMN-14666 canary (this repo, #1783) surfaced: an occ-preflight failure
     SKIPPED the byte-match proof; only a manual rerun made it fire. OCC
     eligibility is already enforced by the independent occ-preflight job in
     ci.yml, so the coupling was redundant as well as harmful.
  3. paths: filter — a path-filtered required check silently does not run on
     PRs that miss the filter.

Canonicalize to match the other five parity gates: runs-on: ubuntu-latest
(hosted-pinned, unconditional), no needs, no paths filter. The gate now
fires on every PR to main/dev and passes/fails purely on its own byte-match
evidence. Canary proven on omnibase_core#1450 (job ran on ubuntu-latest,
passed 13s).
jonahgabriel added a commit that referenced this pull request Jul 19, 2026
…tter (OMN-14783 rec #2) (#1822)

Two live OccCompanionEmitter instances (the local merge_sweep mint path and the
.201 effects lane) run on different hosts with no shared in-process state and
force-push the SAME deterministic auto/<repo>-pr-<pr>-occ-autobind branch, so
"branch exists" is not a discriminator. The OMN-14783 incident was a 5-minute
sequential race (OCC b9251c78 force-pushed over by 28d50bf7) where a stale mint
landed first.

Adds an atomic create-if-absent lease on a git-ref in the shared OCC repo
(onex_change_control) — the only durable surface both producers share. Keyed on
the product PR head SHA (refs/occ-companion-leases/<repo>-pr-<pr>-<head>):
first-acquirer-wins regardless of host; a second concurrent producer no-ops with
ZERO side effects. TTL-based steal (server-authoritative committer timestamp,
skew-free) self-heals a crashed producer's stale lease. Always-on, fail-closed
(no enable/disable flag). Released in the mint's finally so a failed mint does
not wedge the next attempt.

- occ_git_transport: acquire_occ_companion_lease / release_occ_companion_lease
  (shared transport, reusable by node_occ_companion_effect when promoted).
- OccCompanionEmitter._emit_companion_sync: guard before the clone/mutate block,
  wrapped in try/finally (covers both public entry points + all live call sites).
- node_occ_companion_effect: pointer comment for future wiring (no behavior change).
- Fixtures F-C1..F-C7 incl. RED-vs-EXISTS-but-WRONG (guard reverted -> both author)
  and fail-closed (lease transport error -> no author).

Parent OMN-14783. OCC companion owed to Codex. PR-only.

Co-authored-by: test <test@example.com>
jonahgabriel added a commit that referenced this pull request Jul 28, 2026
…bserve toggle

The prior slice shipped defer-on-contention behind
OMNI_OCC_CONTENTION_POLICY=observe|defer, defaulting to `observe`. The
producer that actually mints companions is constructed with no kwargs and
reads no env (handler_pr_lifecycle_fix_runtime.py,
handler_pr_lifecycle_orchestrator.py), so the shipped default reproduced the
exact defect OMN-15247 was filed for: detect the hand-authored companion, log
`would_defer=False`, mint over it anyway. A guard that fires only when an
operator opts in is not a guard
(feedback_optional_input_means_the_check_does_not_exist), and the
displacement it prevents is structurally unrecoverable once the hollow
contract merges.

The toggle is DELETED, not re-defaulted, so no configuration can re-enable
the displacement:
- occ_contention: EnumContentionPolicy and CONTENTION_POLICY_ENV_VAR removed;
  decide_contention(findings) takes no policy argument;
  ModelOccProducerPolicy carries only the check-binding axis.
- occ_companion_emitter: `contention_policy=` constructor arg removed; the
  probe + suppression run unconditionally before the lease (zero side effects
  on defer), same posture as the always-on OMN-14793 lease.
- contract.yaml: OMNI_OCC_CONTENTION_POLICY declaration removed; the guard has
  no env surface to declare. OMNI_OCC_CHECK_BINDING (fix direction #2, a
  selector over check SHAPE, fail-closed inert today) is unchanged.

RED/GREEN by execution, not inspection: the new
test_defer_is_mandatory_with_no_env_and_no_constructor_argument drives the
real _emit_companion_sync on a no-kwargs emitter with no env and a
hand-authored contender. Against the pre-fix tree it FAILS — action is
"authored OCC companion Evidence-Source: OCC#55 ..." with the log line
`provenance=hand_authored policy=observe would_defer=False`. After the change
it returns skip:DEFER_HAND_AUTHORED with zero lease/git/PR/patch calls and no
clone dir. Two anti-regression tests assert the retired opt-in cannot return
through either surface (TypeError on contention_policy=, stale
OMNI_OCC_CONTENTION_POLICY in the env does not disable the guard).

No existing check weakened: the observe-mode tests are deleted with the mode
they covered; the default byte-identity test still asserts byte-for-byte
identical contract/receipt output, now on an uncontended PR (under contention
there are no bytes at all).

Gates on .200 (stickybeatz-studio, rule 11a), patch-transfer mode with sha256
matched on all 5 files both hosts: full suite `-m "not kafka"` 14733 passed /
0 failed, ruff check + format clean, mypy --strict clean (2969 files), full
pre-commit on the changed set green including the blocking OCC emitter golden
gate and the one-OCC-producer gate.
jonahgabriel added a commit that referenced this pull request Jul 28, 2026
…gle (+ content-bound checks, default-OFF) (#1922)

* feat(OMN-15247): OCC autobind defer-on-contention + content-bound checks (both default-OFF)

Builds both OMN-15247 fix directions as default-OFF mechanisms. The shipped
default reproduces today's emitter bytes byte-for-byte.

- omnimarket/src/omnimarket/occ_contention.py (new): provenance classification,
  the files-based contention predicate, the decision rule, and the fail-closed
  policy resolver for OMNI_OCC_CONTENTION_POLICY / OMNI_OCC_CHECK_BINDING.
- omnimarket/src/omnimarket/occ_content_probe.py (new): the OMN-14619 pure
  functions MOVED here (re-exported from handler_occ_state_effect, zero
  behavior change) plus resolve_red_ref (merge base, not pr.base.sha) and the
  measured yamlfmt-stability guard.
- OccCompanionEmitter: contention probe before the lease (zero-side-effect
  defer), content-bound derivation with a mint-time RED/GREEN acceptance bar
  executed through a new raw-exit executor, fail-closed NO_RED_DERIVABLE_CHECK.
- scripts/ci/check_generated_checks_red_derivable.py (new) + new suites wired
  into the EXISTING occ-emitter-golden-gate workflow and pre-commit hook.

Detection runs in both modes of both vars; only enforcement is gated.

Refs OMN-15247

* fix(OMN-15247): make OCC defer-on-contention mandatory — delete the observe toggle

The prior slice shipped defer-on-contention behind
OMNI_OCC_CONTENTION_POLICY=observe|defer, defaulting to `observe`. The
producer that actually mints companions is constructed with no kwargs and
reads no env (handler_pr_lifecycle_fix_runtime.py,
handler_pr_lifecycle_orchestrator.py), so the shipped default reproduced the
exact defect OMN-15247 was filed for: detect the hand-authored companion, log
`would_defer=False`, mint over it anyway. A guard that fires only when an
operator opts in is not a guard
(feedback_optional_input_means_the_check_does_not_exist), and the
displacement it prevents is structurally unrecoverable once the hollow
contract merges.

The toggle is DELETED, not re-defaulted, so no configuration can re-enable
the displacement:
- occ_contention: EnumContentionPolicy and CONTENTION_POLICY_ENV_VAR removed;
  decide_contention(findings) takes no policy argument;
  ModelOccProducerPolicy carries only the check-binding axis.
- occ_companion_emitter: `contention_policy=` constructor arg removed; the
  probe + suppression run unconditionally before the lease (zero side effects
  on defer), same posture as the always-on OMN-14793 lease.
- contract.yaml: OMNI_OCC_CONTENTION_POLICY declaration removed; the guard has
  no env surface to declare. OMNI_OCC_CHECK_BINDING (fix direction #2, a
  selector over check SHAPE, fail-closed inert today) is unchanged.

RED/GREEN by execution, not inspection: the new
test_defer_is_mandatory_with_no_env_and_no_constructor_argument drives the
real _emit_companion_sync on a no-kwargs emitter with no env and a
hand-authored contender. Against the pre-fix tree it FAILS — action is
"authored OCC companion Evidence-Source: OCC#55 ..." with the log line
`provenance=hand_authored policy=observe would_defer=False`. After the change
it returns skip:DEFER_HAND_AUTHORED with zero lease/git/PR/patch calls and no
clone dir. Two anti-regression tests assert the retired opt-in cannot return
through either surface (TypeError on contention_policy=, stale
OMNI_OCC_CONTENTION_POLICY in the env does not disable the guard).

No existing check weakened: the observe-mode tests are deleted with the mode
they covered; the default byte-identity test still asserts byte-for-byte
identical contract/receipt output, now on an uncontended PR (under contention
there are no bytes at all).

Gates on .200 (stickybeatz-studio, rule 11a), patch-transfer mode with sha256
matched on all 5 files both hosts: full suite `-m "not kafka"` 14733 passed /
0 failed, ruff check + format clean, mypy --strict clean (2969 files), full
pre-commit on the changed set green including the blocking OCC emitter golden
gate and the one-OCC-producer gate.
jonahgabriel added a commit that referenced this pull request Aug 1, 2026
…rect its false provenance (#1999)

* fix(OMN-15597): re-pin the AC5 census to the ticket's SHA, correct its provenance

Merged #1998 (3cb2633) pinned the AC5 corpus at onex_change_control@9089ffa9
and asserted -- in the corpus module docstring and in
TestAc5PinnedCorpusReCensus::test_pinned_corpus_is_the_census_the_ticket_names
-- that its 59 values / 33 contracts were the ticket's census "reproduced
exactly". That is false. It was a cardinality coincidence over a different
contract set: OMN-15597's census point is d7b16271 (its own stated 32,593 scan
total is exactly that SHA), and contracts/OMN-15239.yaml and
contracts/OMN-15488.yaml do not exist at 9089ffa9 at all -- so the pinned
corpus structurally could not contain OMN-15488, the live motivating case AC5
exists to protect. A green assertion encoding a false provenance claim is the
same defect class #1998 was opened to close.

Re-pinned to d7b16271 and regenerated with the oracle already committed in this
repo (vendored pre-fix guard rejects AND current guard accepts), via the
fixture's own documented git-archive procedure -- read-only, AC6 respected:

  OCC_CENSUS_SHA                        9089ffa9 -> d7b16271
  OCC_CENSUS_TOTAL_COMMAND_CHECK_VALUES    32564 -> 32593
  class / contracts                        59/33 -> 63/35

The new class is a strict superset of the old 59 (extras: OMN-15239.yaml#0,
OMN-15488.yaml#0/#1/#2). The control at 9089ffa9 reproduces the outgoing
snapshot exactly, so the divergence is the SHA, not the method.

Provenance is now stated rather than implied: the docstring and the renamed
test_pinned_corpus_is_the_ticket_census_point_under_the_committed_oracle say
which oracle at which SHA, and record that the ticket's literal 59/33 was read
with a different oracle (its unbalanced-$( rule, which yields 56/32 here) and
is superseded, not reproduced. New
test_pinned_corpus_covers_every_contract_the_ticket_enumerates makes the
provenance claim falsifiable by containment of the ticket's 33 enumerated
contract names -- something a cardinality coincidence cannot satisfy.

Also corrects the docstring's "one day of OCC commits later" for 1e6b75f8: it
is 76 minutes, same day.

Findings by the #1998 adversarial verifier, independently re-measured and
confirmed by lane G3 (Linear comment 921b6c7b on OMN-15597).

Evidence-Ticket: OMN-15597

* chore(OMN-15597): mint a fresh head so ci.yml re-runs with OCC#5845 merged

The first head ran ci.yml before the OCC companion existed, so
occ-preflight / eligibility failed, OCC Preflight Dependency refused to start
heavy CI, and CI Summary fail-closed -- every test-bearing job was skipped and
this diff had zero Linux-runner proof. OCC#5845 merged 2026-08-01T13:24:08Z
(born-admissible: app/onexbot-occ-writer, both commits authored AND committed
by occ-companion-effect, single-parent, zero human commits) and
occ-preflight / eligibility now passes on the existing head. No diff change.

Evidence-Ticket: OMN-15597
@jonahgabriel
jonahgabriel deleted the jonah/omn-7585-generate-node branch August 25, 2026 18:15
jonahgabriel added a commit that referenced this pull request Aug 31, 2026
…ntracts, real effect boundary, true dependency propagation, runtime reachability (#2237)

Root cause RC-J (2026-08-29 beta off-the-rails analysis rev 2, operator top-three
#2): the canonical assignment layer was already built as ONEX nodes, was
contract-complete and CLI-registered, and was structurally incapable of
executing. The planner shipped; the executor never did.

Contracts honest (A10 step 1)
- wave scheduler: deleted "monitor stalls", the agent_healthcheck integration
  claim, and four publish topics the node never published; publish_topics is now
  exactly the terminal event (published by the runtime). timeout_ms 4h -> 10m and
  implementation_wave / handlers_deferred:true removed — the handler waits on
  nothing and is no longer deferred.
- watchdog: deleted two publish topics the node never published; the two state
  path promises (friction event, dispatch-log line) are now implemented rather
  than deleted.
- new gate scripts/ci/check_contract_publish_parity.py, wired as a pre-commit
  hook and a CI step, burn-down ratchet over
  scripts/ci/contract_publish_parity_baseline.py (131 frozen offenders; the two
  repaired nodes are NOT in it). RED-first: the checker fails on the pre-repair
  wave-scheduler contract and passes after.

Effect boundary (A10 step 2)
- HandlerWaveDispatchStateStore implements ProtocolWaveDispatcher: append-only
  dispatch-lifecycle NDJSON under the resolved state dir plus an observed-outcome
  read-back. dry_run=false no longer raises unconditionally.
- HandlerWatchdogStateStore implements ProtocolWatchdogRecoveryAdapter, including
  record_check, so watchdog.json + dispatch-log/<date>.ndjson are really written
  and their paths reported instead of hardcoded None.

Dependency propagation (A10 step 3)
- waves are computed incrementally from OBSERVED completion; selection is no
  longer completion.
- a non-COMPLETED ticket removes its transitive dependent closure from the
  remaining waves — those tickets are reported BLOCKED and never dispatched.
- a missing dispatcher status is UNREPORTED, never "completed", and forbids
  run_status=COMPLETED; a status outside the enum raises.
- fail_fast is live (ABORTED + SKIPPED); resumed reports a real checkpoint read;
  healthcheck_config (inert and not CLI-expressible) deleted.

Reachability (A10 step 5/6)
- HandlerWatchdogEpicStateReader implements the epic-state loading the request
  model already advertised, so --epic-id does something observable instead of
  raising. Missing state names the exact path.
- substrate: durable dispatch-lifecycle records under $ONEX_STATE_DIR — no
  daemon, no new runner, shaped for the OMN-16176 obligation projection to
  consume when it lands.

Baselines shrunk, never grown: 6 entries out of contract_topic_graph_baseline,
6 out of dep_health_baseline, 5 out of state_coverage_baseline.

Census note (DoD item 6) recorded in the classifier artifact's own header:
node_dispatch_queue_drainer has zero entries there, so a node inventory built
from the classifier alone silently omits it.

Refs OMN-17017. Related OMN-17121 (org-wide publish-parity gate), OMN-16176.

Commit-message provenance (this reword changes no content)

An earlier `git commit --amend` at 2026-08-30T12:03:07-0400 was run from the
wrong worktree: it replaced this commit's message with
"fix(OMN-17187): remove the orphaned error-triaged.v1 emission from
node_runtime_error_triage_effect", an omnibase_infra message, while the tree it
was amending was this omnimarket OMN-17017 change. The mislabel was purely
textual — that same amend ADDED more OMN-17017 content (wave-scheduler contract
tightening, handler_watchdog + handler_wave_scheduler_orchestrator fixes, the new
tests/nodes/node_wave_scheduler_orchestrator/test_dependency_propagation.py, and
the expanded tests/test_node_dispatch_watchdog_orchestrator.py) and touched no
node_runtime_error_triage_effect file at all. OMN-17187's real fix lives in
omnibase_infra and was released separately as 0.38.15; nothing here overlaps it.

This commit therefore carries the full OMN-17017 repair INCLUDING the
dependency-propagation tests added by that amend: the two-wave synthetic epic in
which a wave-1 failure proves wave 2 is never dispatched, the transitive BLOCKED
closure, and the partial-status-map / UNREPORTED cases.

Two fixes found by rebasing this commit onto current dev and re-running:

- scripts/ci/contract_publish_parity_baseline.py: dropped
  node_projection_receipt_gate. OMN-17210 (#2225) landed
  HandlerReceiptGateProjectionRunner on dev, giving that node a real writer for
  its declared snapshot topic, so it is no longer a parity offender. The new
  test_baseline_only_shrinks caught it — the ratchet is a burn-down list, and
  leaving a repaired node frozen in it would have turned it into an allowlist.
  132 -> 131 frozen offenders.
- tests/nodes/node_dispatch_watchdog_orchestrator/test_reachability_and_state_paths.py:
  all three HandlerWatchdogStateStore constructions now pass now_utc=_NOW. They
  injected the frozen clock into the handler but not into the state store, so
  the dispatch-log filename came from the wall clock and the
  `name == "2026-08-30.ndjson"` assertion passed only on the day it was written
  (it failed the moment the clock rolled to 2026-08-31 UTC). The assertion is
  kept as-is and is now deterministic, which also makes it prove that the
  injected clock — not wall time — governs the log name.
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