diff --git a/.github/workflows/governance-acceptance.yml b/.github/workflows/governance-acceptance.yml index 5b84d16..c1e85c4 100644 --- a/.github/workflows/governance-acceptance.yml +++ b/.github/workflows/governance-acceptance.yml @@ -10,6 +10,10 @@ on: description: Same immutable central commit as the reusable workflow reference required: true type: string + require-codex-marker: + description: Fail this observation when the exact-head Codex prerequisite is absent + default: false + type: boolean mode: default: SHADOW type: string @@ -31,6 +35,7 @@ jobs: PR_NUMBER: ${{ inputs.pr-number }} POLICY_REVISION: ${{ inputs.policy-revision }} MODE: ${{ inputs.mode }} + REQUIRE_CODEX_MARKER: ${{ inputs.require-codex-marker }} with: script: | // Trusted reusable workflow code only; never load candidate source. @@ -40,10 +45,13 @@ jobs: const number = Number(process.env.PR_NUMBER); const fail = code => { throw new Error(code); }; const hash = value => typeof value === 'string' && /^[0-9a-f]{40}$/.test(value); + const markerInput = process.env.REQUIRE_CODEX_MARKER; + const markerRequired = markerInput === 'true'; let report = {schema_version: 1, mode: 'SHADOW', merge_authorized: false, + codex_prerequisite: markerRequired || !['true', 'false'].includes(markerInput) ? 'BLOCKED' : 'NOT_REQUIRED', observation: 'UNKNOWN', reason: 'READ_OR_INTEGRITY_FAILURE'}; try { - if (process.env.MODE !== 'SHADOW' || !hash(revision) + if (!['true', 'false'].includes(markerInput) || process.env.MODE !== 'SHADOW' || !hash(revision) || !Number.isSafeInteger(number) || number < 1) fail('INVALID_INPUT'); const {data: content} = await github.rest.repos.getContent({owner: 'QuantStrategyLab', repo: '.github', path: '.github/governance/policy.json', ref: revision}); @@ -197,6 +205,12 @@ jobs: semantic_classification: 'HEURISTIC_NOT_ACCEPTANCE', required_checks: 'NOT_EVALUATED', event_freshness: 'SNAPSHOT_ONLY', baseline_exception: 'UNSUPPORTED', codex_observation: codexObservation(evidence.comments)}; + if (markerRequired) { + report.codex_prerequisite = ['NO_REPORTED_FINDINGS', 'FINDINGS_REPORTED'] + .includes(report.codex_observation) ? 'SATISFIED' : 'BLOCKED'; + if (report.codex_prerequisite !== 'SATISFIED') + core.setFailed('Exact-head Codex review prerequisite is not satisfied'); + } } catch { // Deliberately omit exception text, paths, patches, user bodies and API response data. report = {...report, observation: 'UNKNOWN', reason: 'READ_OR_INTEGRITY_FAILURE'}; diff --git a/README.md b/README.md index 703b654..3316d5e 100644 --- a/README.md +++ b/README.md @@ -23,3 +23,5 @@ Organization-wide files for QuantStrategyLab repositories. Open a pull request. Describe the problem, the change, and the effect on existing repositories. AI assistants and maintainers follow [AGENTS.md](AGENTS.md). - [Governance shadow engine](docs/governance-shadow.md) — reusable report-only review observations. + +- [Collaboration governance](docs/collaboration-governance.md) diff --git a/README.zh-CN.md b/README.zh-CN.md index e632add..a1ec362 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -23,3 +23,5 @@ QuantStrategyLab 各仓库共用的组织级文件。 提交 pull request,说明要解决的问题、改了什么,以及对现有仓库的影响。AI 助手与维护者遵循 [AGENTS.md](AGENTS.md)。 - [Governance shadow engine](docs/governance-shadow.md) — reusable report-only review observations. + +- [协作规则草案](docs/collaboration-governance.md) diff --git a/docs/collaboration-governance.md b/docs/collaboration-governance.md new file mode 100644 index 0000000..f662218 --- /dev/null +++ b/docs/collaboration-governance.md @@ -0,0 +1,69 @@ +# Collaboration governance + +## Merge prerequisites + +The dedicated review-and-merge bot owns PR acceptance and merge disposition. +Before any merge it reads the OPEN PR, full current head and base, changed scope, +native required checks and applicable owner authorization. It also requires a +trusted Codex App comment containing exactly one `codex-review-state:v1` record. +The `code_review.commit_sha` must equal the current full PR head, +`status` must be `completed`, and `has_unresolved_findings` must be `false`. +Both finding flags must be booleans. Findings previously reported and resolved +still require the bot's substantive disposition. Labels, descriptions and a +worker's own receipt cannot substitute for authenticated review evidence. + +Missing, stale, malformed, ambiguous, running or unavailable evidence blocks +merge. Re-read the candidate and evidence immediately before disposition; +changes invalidate the previous snapshot. A head-bound marker does not prove +base or scope acceptance. Independent review, native gates and owner approval +remain separate requirements. Never bypass protection to satisfy this policy. + +Review happens before merge. Never request a new review on a merged PR, +backfill a marker, or treat a later review as retrospective merge permission. +A historical missing-review exception stays recorded. Preserve existing +findings and evidence; an authorized correction uses a new OPEN PR with its +own review. A clean historical report does not prove deployment or runtime. + +## Progress and daily brief + +PR state is the source for source-delivery progress. Read current state, Draft +flag, full head/base, marker binding and required checks from the PR. Describe +OPEN/Draft as work under review, CLOSED without merge as closed, and MERGED as +source integrated. In the same record state whether its exact head has a +completed marker and unresolved findings. Unknown evidence remains unknown. + +Issue #36 becomes a daily brief derived from those readbacks. It is not a +second mutable progress authority. Each entry links its PR where public and +records its observation time, owner, blocker and exact resume condition. +Preserve unresolved production incidents until production readback proves a +fix or the owner explicitly closes them. Source integration cannot close an +incident, PAPER qualification or runtime acceptance by itself. Private work is +shown only as PAS (private), with no private repository link or identity. + +Issue #38 is retired as an instruction and progress channel. Historical content +remains historical; it cannot launch work or authorize an action. Use the +existing coordinator and typed callback receipts for authorized handoffs. +Daily brief describes cadence only: this proposal installs no timer, schedule, +issue editor or external message sender. + +## Workflow prerequisite proposal + +The reusable [observer](../.github/workflows/governance-acceptance.yml) accepts +`require-codex-marker: true` as an opt-in check. It fails unless authenticated, +current-head completed evidence has no unresolved findings. The existing pinned +policy supplies trusted App identities; callers cannot supply their own. +Read or integrity failures fail the check and publish only fixed diagnostic +fields. Two reads reject candidate or evidence drift. Each run is stateless. + +The default remains `false` for existing shadow callers. The workflow always +returns `merge_authorized: false`; a successful prerequisite is necessary +evidence, never merge authority. This proposal changes no caller, trusted +identity, ruleset, branch protection or required-check list. Actual enforcement +requires a separately authorized integration with the dedicated bot and native +controls. Pin both the reusable workflow and policy to the same reviewed +immutable revision before an authorized caller adopts the prerequisite. + +The [skill candidate](skills/quant-collaboration/SKILL.md) contains the matching +operator guidance. Repository presence does not install or update a host skill. +The [legacy exception queue](legacy-governance-exceptions.md) preserves the bounded +historical evidence request without requesting reviews on merged PRs. diff --git a/docs/governance-shadow.md b/docs/governance-shadow.md index 30db82e..b281a12 100644 --- a/docs/governance-shadow.md +++ b/docs/governance-shadow.md @@ -81,3 +81,11 @@ Run `node --test scripts/test-governance-shadow.cjs`, the existing Python checke and secret-scan tests, and `python scripts/check_style.py --phase 2`. The new `Governance shadow tests` workflow exercises the exact inline reusable code with fake API responses. Offline tests do not prove hosted execution or adoption. + +## Optional exact-head prerequisite + +[Collaboration governance](collaboration-governance.md) defines the proposed +`require-codex-marker: true` input. It fails the existing observation job when +trusted completed current-head evidence is absent or unresolved. Existing +callers keep the default `false`. Passing the opt-in check never authorizes +merge; no caller or required-check setting is changed by this source proposal. diff --git a/docs/legacy-governance-exceptions.md b/docs/legacy-governance-exceptions.md new file mode 100644 index 0000000..8e8b2b0 --- /dev/null +++ b/docs/legacy-governance-exceptions.md @@ -0,0 +1,46 @@ +# Legacy missing-review exception queue + +This retained governance exception record tracks the requested eleven-item +historical batch. It does not authorize new reviews on merged PRs, backfilled +markers, corrective implementation or external actions. The first four +references and their order are supplied by the bounded task. The source that +identifies the remaining seven references is missing, so those slots remain +unassigned. This is an incomplete batch, not a claim of eleven verified PRs. + +## Priority and evidence + +The required first-four order is preserved. Production impact determines the +remaining order once their identities are available; do not guess candidates +from a larger search result. Each named item is MERGED with no matching +current-head marker observed in the readback. This says nothing about whether +an earlier independent review occurred or whether the change was deployed. + +| Priority | Reference | Production impact | Evidence disposition | Next condition | +| --- | --- | --- | --- | --- | +| 1 | InteractiveBrokersPlatform #962 | Heartbeat diagnostics and notification policy | Missing current-head marker; runtime policy fix unproved | Retrieve existing evidence; preserve incident until authentic runtime readback | +| 2 | LongBridgePlatform #702 | PAPER identity validation and target selection | Missing current-head marker; historical report has a P2 target-selection finding | Preserve finding and existing repair ownership | +| 3 | QuantPlatformKit #771 | Shared setup contract and release bindings | Missing current-head marker; historical report has two P2 findings | Retain contract/lockfile findings and existing successor evidence | +| 4 | QuantAIService #462 | Monitor configuration and operational diagnosis | Missing current-head marker; historical report is CLEAN, runtime configuration still unproved | Retain clean report separately from the open production incident | +| 5 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | +| 6 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | +| 7 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | +| 8 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | +| 9 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | +| 10 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | +| 11 | Unassigned | Unknown | Original batch reference unavailable | Original batch identity source required | + +## Batch handling contract + +The established review-and-merge bot owns historical evidence disposition. +Retrieve already-existing reports and bind them to the original head and merge +commit; retain missing evidence explicitly. This queue requests evidence +reconciliation only. It does not dispatch review-after-merge. Concrete known +findings may inform a separately authorized new OPEN corrective PR, which must +pass current pre-merge review and gates. Never rewrite historical authorization. + +A completed queue record needs the authenticated original eleven references, +production-impact order after the first four, current source state, original +head/merge bindings in approved evidence storage, existing findings, owner, +blocker and resume condition. Public records show any private reference only +as PAS (private), without links or private identity. No private evidence or +operational resource values belong in this document. diff --git a/docs/skills/quant-collaboration/SKILL.md b/docs/skills/quant-collaboration/SKILL.md new file mode 100644 index 0000000..6fbb09e --- /dev/null +++ b/docs/skills/quant-collaboration/SKILL.md @@ -0,0 +1,28 @@ +--- +name: quant-collaboration +description: Apply PR review prerequisites and daily-brief rules when coordinating QuantStrategyLab PR delivery. Does not authorize dispatch, merge or production changes. +--- +# Quant collaboration + +Follow the repository [AGENTS.md](../../../AGENTS.md) and +[collaboration governance](../../collaboration-governance.md). This is a skill +candidate for review; publishing this file does not install it on a host. + +- Use the current PR state, Draft flag, head/base and checks as source progress. + Issue #36 is a daily derived brief; issue #38 is retired. +- The dedicated review-and-merge bot owns acceptance. Before merge require an + authenticated `codex-review-state:v1` marker with `code_review.commit_sha` + equal to the current head, `status: completed`, boolean finding flags and + `has_unresolved_findings: false`. Re-read state before disposition. Marker + completion alone does not satisfy base/scope review, CI or owner approval. +- Unknown, stale, absent or malformed evidence blocks merge. Never replace + evidence with a label, worker report or edited PR description. +- Review before merge. Never request review on merged PRs or backfill markers. + Retain historical exceptions and findings; corrections need an authorized + new OPEN PR and its own review. +- Keep runtime, PAPER and production incident evidence separate from PR state. + Preserve unresolved production incidents in the daily brief. Display private + work only as PAS (private), without private links or repository identities. +- Use only existing authorized handoff paths. Distinguish dispatched, received + and acknowledged receipts. This skill creates no scheduler, dispatch rights, + configuration changes, merge rights or production authority. diff --git a/scripts/test-governance-shadow.cjs b/scripts/test-governance-shadow.cjs index dbce45d..950a722 100644 --- a/scripts/test-governance-shadow.cjs +++ b/scripts/test-governance-shadow.cjs @@ -29,7 +29,7 @@ async function observe(f = fixture()) { const core = {setFailed: () => {state.failed = true;}, setOutput: () => {}, summary: { addHeading() {return this;}, addCodeBlock(s) {state.summary = s; return this;}, async write() {}}}; const report = await execute(github, {repo: {owner: '', repo: 'sample'}}, core, require, - {env: {MODE: f.mode || 'SHADOW', POLICY_REVISION: R, PR_NUMBER: '1'}}); + {env: {MODE: f.mode || 'SHADOW', POLICY_REVISION: R, PR_NUMBER: '1', REQUIRE_CODEX_MARKER: f.requireMarker === undefined ? 'false' : f.requireMarker}}); assert.equal(report.merge_authorized, false); assert.ok(!state.summary.includes('private token')); return {report, state}; @@ -230,3 +230,51 @@ test('Optional style advice does not require repair', async () => { record.findings = [{kind: 'advisory'}]; f.evidence.reviews[0].body = JSON.stringify(record); assert.equal((await observe(f)).report.observation, 'PENDING_OWNER'); }); + +// The optional prerequisite is necessary evidence only, never merge authority. +test('Required Codex prerequisite fails closed when unconfigured', async () => { + const f = fixture(); f.requireMarker = 'true'; + const {report, state} = await observe(f); + assert.equal(state.failed, true); + assert.equal(report.codex_prerequisite, 'BLOCKED'); +}); +test('Required Codex prerequisite accepts an authenticated completed exact-head marker', async () => { + const {f} = codexFixture(); f.requireMarker = 'true'; + const {report, state} = await observe(f); + assert.equal(state.failed, false); + assert.equal(report.codex_prerequisite, 'SATISFIED'); + assert.equal(report.merge_authorized, false); +}); +for (const mutation of ['missing', 'untrusted', 'stale', 'running', 'unresolved', 'malformed', 'duplicate', 'merged', 'base-drift', 'head-drift', 'invalid-input', 'api']) { + test(`Required marker blocks unsafe evidence: ${mutation}`, async () => { + const {f, entry, record} = codexFixture(); f.requireMarker = 'true'; + if (mutation === 'missing') f.evidence.comments = []; + if (mutation === 'untrusted') entry.performed_via_github_app.id = 54321; + if (mutation === 'stale') record.code_review.commit_sha = 'd'.repeat(40); + if (mutation === 'running') record.code_review.status = 'running'; + if (mutation === 'unresolved') record.code_review.has_unresolved_findings = true; + entry.body = mutation === 'malformed' ? '' + : ``; + if (mutation === 'duplicate') entry.body += entry.body; + if (mutation === 'merged') f.pr.state = 'closed'; + if (mutation.endsWith('-drift')) { + f.current = structuredClone(f.pr); + f.current[mutation === 'base-drift' ? 'base' : 'head'].sha = 'd'.repeat(40); + } + if (mutation === 'invalid-input') f.requireMarker = 'unknown'; + if (mutation === 'api') f.apiError = true; + const {report, state} = await observe(f); + assert.equal(state.failed, true); + assert.equal(report.codex_prerequisite, 'BLOCKED'); + assert.ok(!state.summary.includes('private token')); + }); +} +test('Parallel observations keep no acceptance cache across a moved head', async () => { + const {f} = codexFixture(); f.requireMarker = 'true'; + const moved = structuredClone(f); moved.current = structuredClone(f.pr); + moved.current.head.sha = 'd'.repeat(40); + const [clean, stale] = await Promise.all([observe(f), observe(moved)]); + assert.equal(clean.report.codex_prerequisite, 'SATISFIED'); + assert.equal(stale.report.codex_prerequisite, 'BLOCKED'); + assert.equal(stale.state.failed, true); +});