Skip to content
Draft
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
242 changes: 167 additions & 75 deletions .github/workflows/hourly-product-development.yml

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@

## Automation contract

- Scheduled product development uses OpenCode with `NVIDIA_NIM_API_KEY`; do not use or introduce `COPILOT_GITHUB_TOKEN`.
- Scheduled product development routes OpenCode only through the pinned local
`contextual-orchestrator` gateway and its `orchestrator/free` pool. Provider
credentials remain gateway-owned; do not pass them to OpenCode or introduce
`COPILOT_GITHUB_TOKEN`.
- Do not change the credential contract of the existing independent review agent.
- Prefer the immutable organization-central `.github` workflows over repository-local policy copies.
- Process open PRs before creating another bounded product-development PR.
Expand Down
4 changes: 3 additions & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ the trust kernel.
14. LSP positions use UTF-16 code units; multilingual and emoji ranges are
regression-tested across LF, CRLF, and CR source.
15. Organization-central `.github` workflows own merge governance. Scheduled
product development uses OpenCode with `NVIDIA_NIM_API_KEY`, not Copilot.
product development routes OpenCode through the pinned local
`contextual-orchestrator` gateway's `orchestrator/free` pool, not Copilot
or a direct provider credential.
16. No release occurs while packages remain `0.0.0` under `Unreleased` or while
Studio, cross-platform runtime evidence, signing, SBOM/provenance, and
rollback evidence remain incomplete.
Expand Down
18 changes: 15 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,26 @@ The project follows Semantic Versioning after the first release.

### Changed

- Hourly development's own OpenCode reasoning backend no longer calls NVIDIA
NIM directly. It now vendors a pinned `ContextualWisdomLab/contextual-orchestrator`
gateway sidecar, seeds it from whichever of five organization provider
secrets are present, and routes through the fail-closed, zero-cost
`orchestrator/free` virtual pool, matching the pattern already landed in
`ContextualWisdomLab/.github`'s central review sidecar and
`contextual-orchestrator`'s own hourly loop. The sequential 3-model
`OPENCODE_MODEL_CANDIDATES` fallback list is retired; the gateway's own
auto-discovery now owns fallback across real providers and models. This is
unrelated to DiagramWeave's own product `Contextual Orchestrator` adapter
(`packages/contextual-orchestrator`), which is unchanged. See
[ContextualWisdomLab/DiagramWeave#35](https://github.com/ContextualWisdomLab/DiagramWeave/issues/35).
- Hourly development now routes an open same-repository pull request into an
RCA-driven exact-head remediation session, verifies candidate actions against
live review and Check evidence, publishes only a normal fast-forward repair
after full repository verification, and re-fetches post-push state.
- When no pull request is open, the same credential-isolated OpenCode workflow
uses NVIDIA NIM (`NVIDIA_NIM_API_KEY`) to create at most one bounded product
pull request; it no longer assumes `COPILOT_GITHUB_TOKEN` or the Copilot
Agent Tasks API and rechecks the queue immediately before creation.
uses the gateway-owned `orchestrator/free` pool to create at most one bounded
product pull request; it no longer assumes `COPILOT_GITHUB_TOKEN` or the
Copilot Agent Tasks API and rechecks the queue immediately before creation.

### Security

Expand Down
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Before changing code:
7th-edition references in durable documentation;
5. keep JSON-RPC, source, URI, renderer, filesystem, LLM, and credential inputs
inside their explicit trust boundaries;
6. use OpenCode with `NVIDIA_NIM_API_KEY` for scheduled product-development
6. route scheduled OpenCode work through the pinned local
`contextual-orchestrator` gateway's `orchestrator/free` pool; keep provider
credentials out of the agent process
automation and never introduce `COPILOT_GITHUB_TOKEN`;
7. do not weaken checks, branch protection, review independence, package gates,
or release evidence.
Expand Down
21 changes: 12 additions & 9 deletions docs/operations/hourly-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Independent approval cannot be manufactured. Queued or pending Checks cannot be

### Product-development mode

When the verified inventory contains no open pull request, the workflow may run exactly one bounded OpenCode session against NVIDIA NIM and package one buyer-visible increment as one new pull request. Immediately before creating that PR it re-fetches the queue; if another PR appeared after the initial gate, it fails closed rather than creating duplicate work.
When the verified inventory contains no open pull request, the workflow may run exactly one bounded OpenCode session routed through the local contextual-orchestrator gateway sidecar and package one buyer-visible increment as one new pull request. Immediately before creating that PR it re-fetches the queue; if another PR appeared after the initial gate, it fails closed rather than creating duplicate work.

The delegated session preserves DiagramWeave's source-first manual editing mode, uses or improves Contextual Orchestrator for product LLM work, retains modular MSA compatibility with central `.github`, naruon, and other CWL services, and satisfies the repository's test, coverage, docstring, security, documentation, and design contracts.

Expand All @@ -62,13 +62,15 @@ Do not add a personal access token merely to dispatch another central scheduler

### Remediation and product-development agent

The development agent authenticates to NVIDIA NIM with the `NVIDIA_NIM_API_KEY` organization secret. That value is injected as `NVIDIA_API_KEY` only after the inventory gate selects an actual model-backed path, and only into the OpenCode model-execution step.
The development agent's model traffic is served by a loopback `contextual-orchestrator` gateway sidecar, not by a direct provider call. The workflow vendors `ContextualWisdomLab/contextual-orchestrator` at a pinned commit (`ORCHESTRATOR_PIN_SHA`, the same commit `ContextualWisdomLab/.github`'s central review sidecar and `contextual-orchestrator`'s own hourly loop pin to), installs its hash-pinned dependencies, and starts it with auto-discovery against whichever of five organization provider secrets are present: `BYTEZ_API_KEY`, `NVIDIA_NIM_API_KEY`, `NVIDIA_NIM_API_KEY_SUB`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`. At least one must be present for a model-backed path; a missing individual secret only narrows the gateway's discovered pool.

OpenCode itself never receives a raw provider key. Its isolated configuration contains only the gateway's ephemeral, per-run bearer token, and its model is set to the gateway's fail-closed, zero-cost virtual pool: `contextual_orchestrator_gateway/orchestrator/free`. The gateway's own auto-discovery, not this workflow, owns fallback across real underlying models and providers. Before OpenCode starts, the workflow checks both gateway liveness and one non-empty completion from that virtual route; invalid credentials or an empty usable pool therefore fail before the agent runs.

The built-in token is used by shell steps for inventory, bounded evidence capture, exact-head comparison, branch push, and product PR creation. The OpenCode process is launched with `GH_TOKEN`, `GITHUB_TOKEN`, `REPOSITORY_TOKEN`, and Actions OIDC request variables removed from its environment. Git publication uses an ephemeral masked HTTP header rather than a credential-bearing remote URL.

This replaces the retired Copilot Agent Tasks integration and its `COPILOT_GITHUB_TOKEN` user token. No Copilot subscription is required and the Agent Tasks preview API is not called.

If a model-backed path is selected and the NIM secret is absent, the run fails visibly and creates nothing. Missing credentials are not repaired by inventing new secret names.
If a model-backed path is selected and every one of the five provider secrets is absent, the run fails visibly and creates nothing. Missing credentials are not repaired by inventing new secret names.

## Dry run

Expand All @@ -77,11 +79,11 @@ Use the Actions interface to run either workflow with `dry_run: true`.
- PR maintenance invokes the pinned central scheduler in dry-run mode and does not require a separate repository-dispatch credential.
- The development workflow performs the live PR inventory, selects the mode that a real run would use, and prints the exact bounded agent contract without checking out code, reading the model secret, or invoking a model.

A dry run does not require `NVIDIA_NIM_API_KEY`. It still requires successful pull-request inventory so an API failure cannot be disguised as a successful simulation.
A dry run does not require any of the five gateway provider secrets, including `NVIDIA_NIM_API_KEY`. It still requires successful pull-request inventory so an API failure cannot be disguised as a successful simulation.

## Contextual Orchestrator boundary

All product LLM functionality must use or improve `ContextualWisdomLab/contextual-orchestrator` through the DiagramWeave adapter. The hourly workflow itself does not call the product inference API. Its OpenCode session uses NVIDIA NIM only as the delegated development agent's reasoning backend and instructs the agent to preserve the Contextual Orchestrator product boundary.
All product LLM functionality must use or improve `ContextualWisdomLab/contextual-orchestrator` through the DiagramWeave adapter (`packages/contextual-orchestrator`, see `docs/operations/contextual-orchestrator.md`). The hourly workflow itself does not call that product inference API path. Its OpenCode session's own reasoning backend is served by a separate, workflow-local `contextual-orchestrator` gateway sidecar (see above) routed to the same organization's `orchestrator/free` pool, and the delegated agent is instructed to preserve the product's distinct Contextual Orchestrator boundary rather than conflate the two.

## Failure handling

Expand All @@ -93,9 +95,10 @@ All product LLM functionality must use or improve `ContextualWisdomLab/contextua
- Valid finding has a feasible repository change: reproduce it test-first, implement the smallest correction, run complete verification, push normally, and re-fetch exact-head state.
- Independent approval remains absent: do not synthesize it.
- A required Check is queued or pending: do not call it successful. Continue with the next safe, non-conflicting activity when one exists.
- Dry run: print the selected task contract without reading or requiring the NVIDIA model credential.
- Selected model path lacks `NVIDIA_NIM_API_KEY`: fail before installing or invoking OpenCode.
- Every NVIDIA NIM model candidate fails: reset partial work, fail visibly, and publish nothing.
- Dry run: print the selected task contract without reading or requiring any gateway provider credential.
- Selected model path lacks every one of the five gateway provider secrets: fail before installing or invoking OpenCode.
- The vendored gateway sidecar fails to become healthy, or the checked-out commit does not match `ORCHESTRATOR_PIN_SHA`: fail before invoking OpenCode.
- The gateway-routed development agent fails or times out: fail visibly and publish nothing.
- Repository verification fails: publish nothing.
- A product PR appears between inventory and publication: fail closed and create no duplicate pull request.
- Delayed schedule: rely on the next scheduled run or invoke a manual dry run; do not add a duplicate scheduler.
Expand All @@ -105,4 +108,4 @@ All product LLM functionality must use or improve `ContextualWisdomLab/contextua

To disable autonomous model-backed remediation and product creation, disable `Hourly Product Development` in GitHub Actions or remove its `schedule` event through a pull request. To disable repository-local hourly PR governance, disable `Hourly PR Maintenance`; organization-central event and sweep policies may still process PRs according to organization policy.

Do not remove `NVIDIA_NIM_API_KEY` as an intentional disablement mechanism. Once deterministic gates select the model path, a missing required credential is an operational failure and remains visible rather than producing a false-green skip.
Do not remove `NVIDIA_NIM_API_KEY` or the other four gateway provider secrets as an intentional disablement mechanism. Once deterministic gates select the model path, a fully missing credential set is an operational failure and remains visible rather than producing a false-green skip.
36 changes: 8 additions & 28 deletions tests/hourly-runtime-budget-contract.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,21 @@ import test from 'node:test';

import { readRepositoryFile } from './helpers/repository-contract.js';

const orchestrationReserveSeconds = 30 * 60;

test('hourly development budget can execute every sequential model fallback', async () => {
test('hourly development leaves model duration to the three-hour job budget', async () => {
const workflow = await readRepositoryFile(
'.github/workflows/hourly-product-development.yml',
);

const jobTimeoutMatch = workflow.match(
/runs-on: ubuntu-latest\n timeout-minutes: (\d+)/,
);
const modelTimeoutMatch = workflow.match(
/OPENCODE_RUN_TIMEOUT_SECONDS: ["'](\d+)["']/,
);
const candidatesMatch = workflow.match(
/OPENCODE_MODEL_CANDIDATES: >-\n((?: \S.*\n)+) OPENCODE_RUN_TIMEOUT_SECONDS:/,
);

assert.ok(jobTimeoutMatch, 'hourly development must declare a job timeout');
assert.ok(modelTimeoutMatch, 'hourly development must bound each model attempt');
assert.ok(candidatesMatch, 'hourly development must declare its model fallback pool');

const jobTimeoutSeconds = Number(jobTimeoutMatch[1]) * 60;
const modelTimeoutSeconds = Number(modelTimeoutMatch[1]);
const modelCandidates = candidatesMatch[1]
.trim()
.split('\n')
.map((candidate) => candidate.trim())
.filter(Boolean);
const requiredSeconds =
modelCandidates.length * modelTimeoutSeconds + orchestrationReserveSeconds;

assert.ok(modelCandidates.length > 1, 'the fallback pool must remain explicit');
assert.ok(
jobTimeoutSeconds >= requiredSeconds,
`job timeout ${jobTimeoutSeconds}s cannot cover ${modelCandidates.length} sequential ` +
`model attempts at ${modelTimeoutSeconds}s plus ${orchestrationReserveSeconds}s reserve`,
assert.ok(Number(jobTimeoutMatch[1]) >= 180);
assert.doesNotMatch(workflow, /OPENCODE_RUN_TIMEOUT_SECONDS/);
assert.doesNotMatch(workflow, /timeout --kill-after=30s/);
assert.doesNotMatch(
workflow,
/OPENCODE_MODEL_CANDIDATES/,
'model-level fallback belongs to the contextual-orchestrator gateway now, not a repository-level candidate list',
);
});
Loading
Loading