From ecf8bd621b4c05fbad9d89085de536d32c0b0eee Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 10:15:31 +0900 Subject: [PATCH 1/5] fix(actions): align hourly runbook with central admission --- .../HOURLY_NIM_PRODUCT_DEVELOPMENT.md | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/operations/HOURLY_NIM_PRODUCT_DEVELOPMENT.md b/docs/operations/HOURLY_NIM_PRODUCT_DEVELOPMENT.md index cd78f1ca8..d9704fd8b 100644 --- a/docs/operations/HOURLY_NIM_PRODUCT_DEVELOPMENT.md +++ b/docs/operations/HOURLY_NIM_PRODUCT_DEVELOPMENT.md @@ -1,17 +1,20 @@ # 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 @@ -19,7 +22,7 @@ missing provider key, or a missing Maintainer App configuration produces a stabl 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): @@ -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 @@ -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. @@ -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. From bfda6a2685edd35b9ba3a36046d7f617eacc67dc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 10:16:33 +0900 Subject: [PATCH 2/5] fix(actions): align central admission quality contract --- tests/quality/test_hourly_nim_product_development.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/quality/test_hourly_nim_product_development.py b/tests/quality/test_hourly_nim_product_development.py index e2a1a03a0..fe14320ca 100644 --- a/tests/quality/test_hourly_nim_product_development.py +++ b/tests/quality/test_hourly_nim_product_development.py @@ -36,13 +36,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 }}", @@ -77,6 +77,7 @@ def test_hourly_workflow_schedule_credentials_and_queue_gate(self) -> None: "ContextualWisdomLab/TEPP", ): self.assertIn(token, text) + self.assertNotIn("\n schedule:\n", text) for token in ("discover_all_models", "register_credential", "PROVIDER_CREDENTIAL_NAMES"): self.assertIn(token, bootstrap) self.assertNotIn("COPILOT_GITHUB_TOKEN", text) @@ -278,6 +279,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.""" From 0e58e29da56569ae98c073b33f1187ffc6f7855c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 10:16:51 +0900 Subject: [PATCH 3/5] docs(actions): record central admission contract repair --- CHANGELOG.d/central-hourly-admission-contract.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGELOG.d/central-hourly-admission-contract.md diff --git a/CHANGELOG.d/central-hourly-admission-contract.md b/CHANGELOG.d/central-hourly-admission-contract.md new file mode 100644 index 000000000..d7c8a9aa4 --- /dev/null +++ b/CHANGELOG.d/central-hourly-admission-contract.md @@ -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. From 3c481db57e6c4e5fab67d48414cb36aa24c79265 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 12:32:41 +0900 Subject: [PATCH 4/5] test: validate central workflow trigger structure --- .../test_hourly_nim_product_development.py | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/quality/test_hourly_nim_product_development.py b/tests/quality/test_hourly_nim_product_development.py index fe14320ca..18380af83 100644 --- a/tests/quality/test_hourly_nim_product_development.py +++ b/tests/quality/test_hourly_nim_product_development.py @@ -24,6 +24,36 @@ 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}:" + matches = [index for index, line in enumerate(lines) if line == header] + 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.""" @@ -77,7 +107,7 @@ def test_hourly_workflow_central_admission_credentials_and_queue_gate(self) -> N "ContextualWisdomLab/TEPP", ): self.assertIn(token, text) - self.assertNotIn("\n schedule:\n", 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) @@ -86,6 +116,14 @@ def test_hourly_workflow_central_admission_credentials_and_queue_gate(self) -> N 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_hourly_workflow_separates_three_runner_trust_boundaries(self) -> None: """Separate model execution, verification, and late publication authority.""" From 794ba9e6dda9f043aa499920fdf609b81b075d7e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 13:18:55 +0900 Subject: [PATCH 5/5] fix(actions): parse commented block-style workflow headers --- .../test_hourly_nim_product_development.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/quality/test_hourly_nim_product_development.py b/tests/quality/test_hourly_nim_product_development.py index 18380af83..ae429178e 100644 --- a/tests/quality/test_hourly_nim_product_development.py +++ b/tests/quality/test_hourly_nim_product_development.py @@ -29,7 +29,19 @@ def _top_level_mapping_child_keys(text: str, key: str) -> set[str]: lines = text.splitlines() header = f"{key}:" - matches = [index for index, line in enumerate(lines) if line == header] + + 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]] = [] @@ -124,6 +136,20 @@ def test_schedule_detection_is_independent_of_yaml_indentation_width(self) -> No 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."""