Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.d/central-hourly-admission-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed protected-main commercial-development contract drift introduced by #490: the TEPP entrypoint is now documented and tested as dispatch-only under the organization-level coordinator, while retaining fail-closed queue, credential, and publication boundaries.
40 changes: 22 additions & 18 deletions docs/operations/HOURLY_NIM_PRODUCT_DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
# Hourly Contextual Orchestrator Product Development

The hourly contextual-orchestrator product-development workflow proposes one bounded
commercial-quality increment when the repository has no open pull request or open
issue. It is
separate from the deterministic minute-17 quality sentinel and never merges,
releases, deploys, approves, or changes reviewer credentials.
The repository-local contextual-orchestrator product-development workflow is a
commercial-development execution entrypoint. Organization-level coordination owns
the recurring admission cadence; the TEPP entrypoint proposes one bounded
commercial-quality increment only when it is dispatched and the repository has no
open pull request or open issue. It is separate from the deterministic minute-17
quality sentinel and never merges, releases, deploys, approves, or changes reviewer
credentials.

## Schedule and queue behavior

`.github/workflows/hourly-nim-product-development.yml` runs at minute 47 of every
hour and supports `workflow_dispatch` with `dry_run=true`. The nonzero minute
avoids the busiest scheduler boundary. A repository-scoped concurrency group
does not cancel an active run.
`.github/workflows/hourly-nim-product-development.yml` is intentionally dispatch-only
and carries the `# cwl-org-commercial-entrypoint: v1` marker consumed by the central
commercial-development coordinator. The repository workflow does not own a cron
schedule. It supports `workflow_dispatch` with `dry_run=true`, and a repository-scoped
concurrency group does not cancel an active run.

Before checkout or model execution, the proposal job reads at most one open pull
request and one open issue. Unreadable inventory, any open PR or issue, any
missing provider key, or a missing Maintainer App configuration produces a stable
fail-closed no-op. A dry run may print the task contract without credentials.

When a PR or issue exists, normal review → repair → exact-head Checks → merge
governance owns the hour. The scheduler does not create a competing branch.
governance owns the hour. The coordinator does not create a competing branch.

Current executable queue (2026-08-27T10:20Z snapshot; live state supersedes):

Expand Down Expand Up @@ -55,9 +58,9 @@ Do not place GitHub App credentials in the proposal or verifier jobs. Do not
reuse the existing review App or alter its variable, secret, identity, or
provider route. Do not configure `COPILOT_GITHUB_TOKEN`.

A manual dry run verifies scheduling, queue, and prompt contracts without model
or publication credentials. Missing production credentials leave the hourly
developer disabled rather than falling back to `GITHUB_TOKEN`.
A manual dry run verifies admission, queue, and prompt contracts without model
or publication credentials. Missing production credentials leave the entrypoint
disabled rather than falling back to `GITHUB_TOKEN`.

## Three-runner trust boundary

Expand Down Expand Up @@ -160,10 +163,11 @@ write token.

## Disablement and rollback

Disable scheduled development by disabling the workflow, removing its schedule,
or removing any one of the five provider credentials. Removing any provider key
stops model execution; removing the Maintainer App values stops publication.
The minute-17 deterministic quality sentinel continues independently.
Disable commercial-development execution by disabling central coordinator
admission for TEPP, disabling the repository entrypoint workflow, or removing
any one of the five provider credentials. Removing any provider key stops model
execution; removing the Maintainer App values stops publication. The minute-17
deterministic quality sentinel continues independently.

Rollback a faulty workflow through a reviewed revert PR. Do not edit branch
protection, review workflows, or release workflows as an incident shortcut.
Expand All @@ -177,7 +181,7 @@ references them.
inference broker could keep upstream secrets outside the runner.
- Each configured provider may process repository source; operators must review
confidentiality, retention, regional, and contractual obligations for every
provider before enabling the schedule.
provider before enabling coordinator admission.
- The verifier executes untrusted code on an ephemeral hosted runner with
outbound network access, but receives no publication, provider, OIDC,
artifact/cache runtime, command-file, or reviewer credential.
Expand Down
72 changes: 69 additions & 3 deletions tests/quality/test_hourly_nim_product_development.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,48 @@ def _text(path: Path) -> str:
return path.read_text(encoding="utf-8")


def _top_level_mapping_child_keys(text: str, key: str) -> set[str]:
"""Return immediate child keys for one block-style top-level YAML mapping."""

lines = text.splitlines()
header = f"{key}:"

def is_block_header(line: str) -> bool:
if line[:1].isspace() or not line.startswith(header):
return False
suffix = line[len(header) :]
if not suffix:
return True
if not suffix[0].isspace():
return False
remainder = suffix.strip()
return not remainder or remainder.startswith("#")

matches = [index for index, line in enumerate(lines) if is_block_header(line)]
assert len(matches) == 1, f"expected one block-style {header!r} mapping"

entries: list[tuple[int, str]] = []
for line in lines[matches[0] + 1 :]:
stripped = line.strip()
if not stripped or stripped.startswith("#"):
continue
indent = len(line) - len(line.lstrip(" "))
if indent == 0:
break
entries.append((indent, stripped))

assert entries, f"top-level {header!r} mapping must not be empty"
child_indent = min(indent for indent, _entry in entries)
child_keys: set[str] = set()
for indent, entry in entries:
if indent != child_indent:
continue
child_key, separator, _value = entry.partition(":")
assert separator, f"expected mapping entry under {header!r}: {entry!r}"
child_keys.add(child_key.strip("'\""))
return child_keys


def _parser_module() -> ModuleType:
"""Load the trusted pull-request metadata parser as a covered module."""

Expand All @@ -36,13 +78,13 @@ def _parser_module() -> ModuleType:
class HourlyNimProductDevelopmentContractTests(unittest.TestCase):
"""Structural tests for the credential-separated product-development loop."""

def test_hourly_workflow_schedule_credentials_and_queue_gate(self) -> None:
"""Run at minute 47 with provider discovery and fail closed around inventory."""
def test_hourly_workflow_central_admission_credentials_and_queue_gate(self) -> None:
"""Stay dispatch-only under central admission and fail closed around inventory."""

text = _text(WORKFLOW)
bootstrap = _text(BOOTSTRAP)
for token in (
'cron: "47 * * * *"',
"# cwl-org-commercial-entrypoint: v1",
"workflow_dispatch:",
"dry_run:",
"hourly-nim-product-development-${{ github.repository }}",
Expand Down Expand Up @@ -77,6 +119,7 @@ def test_hourly_workflow_schedule_credentials_and_queue_gate(self) -> None:
"ContextualWisdomLab/TEPP",
):
self.assertIn(token, text)
self.assertEqual(_top_level_mapping_child_keys(text, "on"), {"workflow_dispatch"})
for token in ("discover_all_models", "register_credential", "PROVIDER_CREDENTIAL_NAMES"):
self.assertIn(token, bootstrap)
self.assertNotIn("COPILOT_GITHUB_TOKEN", text)
Expand All @@ -85,6 +128,28 @@ def test_hourly_workflow_schedule_credentials_and_queue_gate(self) -> None:
self.assertNotIn("gh pr merge", text)
self.assertNotIn("gh release create", text)

def test_schedule_detection_is_independent_of_yaml_indentation_width(self) -> None:
"""Reject a repository-local schedule regardless of valid block indentation."""

for indent in (" ", " "):
candidate = f'on:\n{indent}schedule:\n{indent} - cron: "47 * * * *"\n'
with self.subTest(indent=len(indent)):
self.assertEqual(_top_level_mapping_child_keys(candidate, "on"), {"schedule"})

def test_block_header_accepts_yaml_trivia_and_rejects_flow_value(self) -> None:
"""Recognize block headers with valid trivia without admitting flow-style values."""

for header in ("on:", "on: ", "on: # central admission"):
with self.subTest(header=header):
candidate = f"{header}\n workflow_dispatch:\n"
self.assertEqual(
_top_level_mapping_child_keys(candidate, "on"),
{"workflow_dispatch"},
)

with self.assertRaisesRegex(AssertionError, "expected one block-style"):
_top_level_mapping_child_keys("on: {workflow_dispatch: {}}\n", "on")

def test_hourly_workflow_separates_three_runner_trust_boundaries(self) -> None:
"""Separate model execution, verification, and late publication authority."""

Expand Down Expand Up @@ -278,6 +343,7 @@ def test_hourly_queue_reflects_current_open_inventory(self) -> None:
for pull_request in (93, 94, 97, 101, 102, 104, 108, 109, 111, 112):
with self.subTest(pull_request=pull_request):
self.assertNotIn(f"PR #{pull_request}", runbook)

def test_bootstrap_registers_each_provider_key_and_removes_environment_values(self) -> None:
"""Exercise the real bootstrap loop with a key-counting KV double."""

Expand Down
Loading