Skip to content

Decision: Authenticate lifecycle wake-up without Actions write #131

Description

@Niko4417

Parent Epic: #49

Planning contract

  • Contract version: v13

Decision question and authority

  • Decision to resolve: Define a GitHub-native wake topology that starts the protected lifecycle coordinator and its exact protected producers from dev without actions: write, a new identity, or a second lifecycle writer; provides an authenticated forward-recovery entry point; and preserves ADR-0011 record authentication plus exact per-issue and provider-budget serialization.
  • Why it must be decided now: Issue Protected lifecycle request ingress and activated event wiring #51 v5 proved against repository run 30393476770 that a reusable workflow retains its top-level caller run identity. The rejected v2 dispatch router then failed independent audit because actions: write can cancel, rerun, enable, disable, and delete workflow evidence. The accepted v3 design was returned to planning when primary-source audit proved that review-event refs, Actions check recursion suppression, resolver artifact transport, and source-specific permissions required semantic source and trust-boundary changes. The v4 audit then proved that GitHub scheduled runs can be delayed or dropped, so review liveness has no one-hour upper bound. Post-publication review of ADR-0012 at PR docs: decide protected lifecycle wake topology #132 then proved that v5 omitted the input-preserving producer invocation path, made explicit recovery unreachable, and exempted provider-reading resolvers from ADR-0011's repository-wide budget. Fresh exact-head review after v6 promotion proved that stable rereads did not reject a command edited before validation and that exact-cardinality recovery-command discovery lacked a feasible bound. The v7 cursor-resumption response was returned to planning when independent audit proved that double-reading 100 pages exceeds ADR-0011's 150-request recovery ceiling and that its existing version-1 recovery-progress fields cannot bind resumed work to the original human comment. Version 8 replaced history-wide cardinality with an individually authenticated exact-comment locator and recovery-target idempotency. Fresh ready-state review at exact PR docs: decide protected lifecycle wake topology #132 head 7a1cacb4fca06d84ef8f40e104110ef01cffbda8 then proved that selecting the lowest syntactic fallback candidate before actor authorization lets an older unauthorized command starve a later valid command. Version 9 adds a bounded stable actor-and-permission prefilter before deterministic fallback selection. Independent v9 audit then proved that the producer interface still named domain types rather than GitHub workflow_call wire primitives, leaving nullable values and canonical bytes without a deterministic transport encoding. Version 10 freezes the complete string-only wire schema and canonical encodings. Fresh exact-head Qodo review at PR docs: decide protected lifecycle wake topology #132 head cf08e00916c8a9933b6a76ac6a5baf1658e76ceb then proved that the wire accepted any positive producer contract version and referenced a target canonical form that ADR-0011 never defined. Version 11 freezes the exact producer-to-version mapping and a self-contained target-branch grammar with byte-exact authority checks. Independent v11 audit then proved that the positive target regex still admitted provider-invalid epic/a..b and epic/a.lock refs. Version 12 additionally rejects .. anywhere and any slash-delimited component ending .lock, with first-rejected-complement tests. Fresh exact-head Qodo review at PR docs: decide protected lifecycle wake topology #132 head 03a95c50fa5ff1a5deaca67d73741ca452f61398 then proved that the protected-producer wire incorrectly required a positive attempt even though ADR-0011 and the canonical bootstrap generation permit attempt 0. Version 13 separates positive provider IDs from the non-negative safe attempt sequence and pins bootstrap zero plus rejected decimal complements.
  • Decision owner: Niko, repository owner and authorized maintainer, who explicitly selected the protected caller plus exact reusable-callee design with no Actions-write permission and no additional GitHub account, App, PAT, machine user, broker, database, or hosted service.
  • Agent Planning Baseline, Decision Addendum, parity, risk, or incident reference: One-effect/one-owner, strictest-policy, typed bounded boundaries, body-free evidence, fail-closed recovery, least privilege, and machine-enforced production composition. This is repository governance and does not change Native product scope or parity.
  • Relevant accepted ADRs and repository evidence: ADR-0003, ADR-0004, ADR-0009, ADR-0010, ADR-0011, AGENTS.md, docs/qa/issue-lifecycle.md, epic Epic: Contract-as-Code migration and lifecycle activation cutover (ADR-0003/ADR-0004) #49 v8, issue Protected lifecycle request ingress and activated event wiring #51 v5, issue Signed activation switch, in-flight continuity, and integrated acceptance #55 v6, PR docs: define authenticated lifecycle handoff record protocol #130, protected dev at 69b60454c2ecd6895ffda03ba64c8d6c565cd8e8, actual run 30393476770, GitHub reusable-workflow, OIDC, event, recursion, artifact, permission, workflow-run, and job-concurrency documentation, focused Protected lifecycle request ingress and activated event wiring #51 protocol evidence, successive independent Decision: Authenticate lifecycle wake-up without Actions write #131 audit rounds, PR docs: decide protected lifecycle wake topology #132 reviews 4803653313, 4803986996, and 4804656859.
  • Required resulting record: ADR-0012 defining the exact protected caller, reusable lifecycle coordinator, nested protected-producer chain, authenticated maintainer recovery request with never-edited exact-comment evidence, immutable request identity, recovery-target idempotency, and bounded non-starving fallback discovery, freezes the complete GitHub workflow_call producer wire schema, the exact producer-to-version mapping, the self-contained canonical target grammar, and all canonical encodings, including bootstrap attempt zero, and records its narrow amendment to ADR-0011 authentication and serialization wording.

Constraints and non-negotiables

  • Product and user constraints: Preserve all nine canonical lifecycle states, the complete allowed edge graph, existing transition owners, readiness separation, and human-only dev. A wake carries no requested lifecycle state, lane, activation decision, readiness conclusion, merge authority, or evidence-backed outcome.
  • Architecture and dependency constraints: .github/workflows/lifecycle-wakeup.yml is the sole top-level lifecycle caller. Direct caller events are exactly the closed issues, pull_request_target, plain and pull-request issue_comment, external-provider check_run, workflow_run, and hourly schedule classes below. A read-only resolver derives only canonical issue locators before authority serialization. For a recovery-command wake, the typed locator may additionally carry the untrusted numeric comment ID from that event; the ID grants no authority and is re-fetched under the per-issue lock. Every resolver that makes provider requests acquires issue-lifecycle-provider-budget as its sole group; the zero-request issue resolver does not. A coordinate job then acquires issue-lifecycle-{decimal issue number} with queue: max and invokes only ./.github/workflows/issue-lifecycle.yml. The coordinator starts the closed producer set only through exact local reusable calls to ./.github/workflows/pr-contract.yml and ./.github/workflows/contract-publication.yml, passing ADR-0011's complete generation, attempt, request, fence, repository, issue, pull-request, head, target, and expected-producer inputs. Every producer workflow_call input uses the GitHub primitive string, in this exact order: schema_version, producer_contract_version, repository, issue_number, pull_request_number, exact_head_sha, exact_target, generation_bytes_base64, generation_bytes_sha256, generation_identity, attempt, phase_fence_comment_id, phase_fence_digest, generation_request_comment_id, generation_request_digest, request_identity, request_payload_digest, expected_producer. schema_version is the literal 1; producer_contract_version is the literal 1 for each of issue-contract-current, pr-contract, and contract-publication, with every other producer/version pair unsupported; issue and comment-ID strings are canonical positive safe decimal integers; attempt is a canonical non-negative safe decimal integer, including bootstrap 0; pull_request_number is empty for explicit null or canonical positive decimal; exact_head_sha is empty for explicit null or exactly 40 lowercase hexadecimal characters; exact_target is empty for explicit null, the literal dev, or an ASCII epic branch matching epic/[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?(?:/[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)*; a non-empty value contains no .., has no slash-delimited component ending .lock, has no refs/heads/ prefix or normalization step, and must equal both the current accepted issue delivery target and, when a pull request exists, its provider base-ref bytes exactly; generation_bytes_base64 is strict padded RFC 4648 base64 that decodes to the exact non-empty ADR-0004 canonical generation bytes and re-encodes byte-identically; every digest or identity is exactly 64 lowercase hexadecimal characters; and expected_producer is one closed producer enum. The repository string is exactly oscharko-dev/Keiko-Native. generation_bytes_base64 is at most 65,536 UTF-8 bytes and every other input is at most 512 UTF-8 bytes. Missing, extra, reordered, incorrectly typed, noncanonical, empty where prohibited, first-over-bound, decode-invalid, or digest-mismatched input fails before provider access. Provider-intensive coordinator and producer jobs acquire issue-lifecycle-provider-budget only after the caller-held per-issue lock.
  • Security, privacy, regulatory, and operational constraints: The wake path has no actions: write. Protected caller authentication uses OIDC workflow_ref, workflow_sha, event ref and sha; REST head_sha is event correlation only. Reusable coordinator and nested producer authentication also require exact job_workflow_ref, job_workflow_sha, the closed referenced-workflow chain, and the same protected dev SHA. The caller permission ceiling adds only statuses: write for the two closed status-producing contract results; no nested callee may elevate it. Explicit recovery is one Unicode-NFC single-line issue_comment command consisting of the literal /keiko-native lifecycle-recovery v1 target=sha256: followed by exactly 64 lowercase hexadecimal characters and no other byte. It names an ADR-0011 recovery-target digest and must be authored by exactly Niko4417 with numeric user ID 159039192 or oscharko with numeric user ID 59687448, type User, and live repository permission maintain or admin. The direct event supplies only the issue number and numeric comment-ID locator. Inside the per-issue lock, the coordinator fetches that exact comment twice and requires identical body, actor, target, createdAt, updatedAt, lastEditedAt, editor, and includesCreatedEdit; createdAt must equal updatedAt, lastEditedAt and editor must be null, and includesCreatedEdit must be false. It then derives a domain-separated SHA-256 authorized-recovery-request identity over repository numeric ID, issue number, comment ID, exact NFC-body digest, creation timestamp, author numeric ID and type, and recovery-target identity. The coordinator independently reconstructs the orphan, predecessor, current authority, and target before creating a new attempt. At most one authenticated recovery record may consume a recovery-target identity; the existing ADR-0011 version-1 authorized_request_identity slot binds the derived request, so no record schema changes. Duplicate or reordered commands serialize under the issue lock: the first valid settlement consumes the target and every later command is a replay no-op, irrespective of provider scheduling order. Non-comment wakes and the schedule may inspect only ADR-0011's existing stable two-page normal comment window. Before selection, they prefilter stable comments by exact command grammar, never-edited predicates, actor type User, immutable numeric actor-ID membership in the protected two-principal allowlist, and two agreeing live-permission reads per distinct allowlisted actor. At most two actors and four prefilter permission requests are possible. Only candidates whose actor retains maintain or admin remain; the coordinator then processes at most one candidate, deterministically choosing the lowest numeric comment ID. The prefilter grants no recovery authority and the selected comment still undergoes the complete six-request authentication. The exact event locator takes precedence. A lost command outside that bounded window is never searched through unbounded history—the maintainer posts a fresh never-edited command. Any edit, deletion, identity or permission change, unstable reread, malformed candidate, target mismatch, or already consumed target produces no record or effect. Resolver permissions are split to the minimum per closed event subtype. Repository permissions alone do not deny runner-artifact upload, so resolver structure must remove ACTIONS_RUNTIME_TOKEN, ACTIONS_RUNTIME_URL, and ACTIONS_RESULTS_URL before its sole repository command and machine-deny every upload action, artifact client, extra action, command, or step.
  • Supported platforms and reference environments: GitHub.com, protected GitHub Actions workflows from dev, Node.js 24.18.x, npm 11.16.x, macOS operator verification, and GitHub-hosted Ubuntu. Native desktop platforms are unaffected.
  • Explicit non-goals: A new account, installed App, PAT, machine user, broker, database, hosted service, generic event bus, actions: write, coordinator-initiated caller or producer workflow dispatch, repository dispatch, direct review-event caller, second lifecycle writer, unauthenticated or non-maintainer recovery, history-wide or cursor-resumed recovery-command enumeration, caller-selected policy, branch administration, auto-merge, queue enrollment, or automated dev effect. The separately accepted top-level Contract Publication manual source remains outside this lifecycle invocation path.

The exact direct caller event set is:

  • issues: assigned, closed, edited, labeled, reopened, unassigned, unlabeled;
  • pull_request_target: opened, edited, reopened, synchronize, ready_for_review, converted_to_draft, closed;
  • issue_comment: created, edited, deleted, split by the payload's plain-issue versus pull-request subtype;
  • external-provider check_run: completed, rerequested;
  • workflow_run: completed for only the closed source table below; and
  • schedule: hourly at minute 17.

pull_request_review and pull_request_review_comment are excluded because GitHub assigns their runs the pull-request merge ref and SHA. The protected scan is scheduled nominally hourly at minute 17 and is the normal reconciliation path for review and conversation changes. GitHub may delay or drop a run; no maximum review latency is promised, and liveness resumes on the next successful scan or another allowed event.

The exact workflow_run source set is:

Source class Source path Exact display name Accepted source event
Governance .github/workflows/issue-readiness.yml Issue readiness issues
Governance .github/workflows/pr-contract.yml Pull request contract pull_request_target
Governance .github/workflows/contract-publication.yml Contract publication (inert) workflow_dispatch
Evidence .github/workflows/ci.yml CI pull_request
Evidence .github/workflows/codeql.yml CodeQL pull_request
Evidence .github/workflows/dependency-review.yml Dependency Review pull_request
Evidence .github/workflows/osv-scanner.yml OSV dependency scan pull_request

Governance sources publish the exact bounded locator artifact. Evidence sources are untrusted run and associated-pull-request locators; their code and conclusions grant no authority. GitHub Actions-created checks do not enter through check_run because GitHub suppresses that recursion.

The exact resolver profiles and limits are:

Resolver Accepted subtype Exact non-none permissions Request ceiling
Issue issues; plain-issue issue_comment contents: read 0
Pull request pull_request_target; pull-request issue_comment; external check_run contents: read, pull-requests: read 2
Governance completion governance workflow_run actions: read, contents: read 6
Evidence completion evidence workflow_run actions: read, contents: read, pull-requests: read 4
Schedule schedule contents: read, issues: read, pull-requests: read 8

Every selected scalar locator string is at most 64 UTF-8 bytes; a PR body used only for accepted-issue extraction is at most 65,536 bytes; one canonical locator is at most 512 bytes; one locator archive is at most 65,536 downloaded bytes with exactly one regular file of at most 512 bytes. Schedule uses per_page=100, at most two pages each of issues and pull requests, repeats the complete enumeration once, emits at most 200 unique ascending issue numbers with no other matrix dimension, and rejects the third page, 201st locator, ninth request, partial enumeration, or first over-bound byte. This remains below GitHub's 256-job matrix maximum.

Evaluation journey

  • Applicability: Not applicable — repository governance only; no Native desktop UI or user-facing product behavior.
  • Actor and user goal: A protected direct repository event, closed workflow completion, or protected scheduled scan wakes the sole reusable lifecycle coordinator without deciding what the change means.
  • Representative starting state and sanitized test data: Synthetic repository, issue and pull-request numbers, closed event kinds and subtypes, bounded locator bytes, workflow/run/attempt identities, exact protected workflow/ref/SHA constants, recovery comment ID, createdAt/updatedAt/lastEditedAt/editor/includesCreatedEdit, authorized-request identity and consumed-target fixtures, and first-over-limit values; no bodies beyond bounded synthetic fixtures, reasons, credentials, or provider payloads.
  • Observable path and failure or recovery states: The protected caller selects one minimum-permission resolver, which emits one canonical issue locator or a complete bounded scheduled set. A provider-reading resolver first serializes its bounded reads through the repository-wide budget as its sole lock. Each coordinate job then acquires the exact per-issue group and calls the sole reusable coordinator. The coordinator independently reloads and authenticates all authority and evidence before any record or effect, then invokes each required protected producer through its exact nested reusable interface after validating the complete string-only wire schema and canonical null, supported producer-version, positive-ID and non-negative-attempt decimal, commit, target-branch, rejected ../.lock complements, base64, digest, and producer encodings; every provider-intensive nested job acquires the provider-budget group second. Duplicate wakes reconcile idempotently. An exact allowlisted-maintainer recovery comment triggers only typed issue-and-comment locator resolution; the locked coordinator fetches that exact comment twice, rejects every ever-edited command, derives the immutable authorized-request identity, authenticates the exact recovery target, and creates a new attempt only when no authenticated recovery record has already consumed that target. Duplicate commands become replay no-ops. Non-comment reconciliation first removes syntactically invalid, edited, non-allowlisted, and non-maintainer candidates using stable page facts plus at most four actor-permission reads, then considers at most one deterministic lowest-ID candidate from the existing stable two-page normal window and never scans unbounded history. Wrong caller/callee/producer/ref/SHA/repository, unsupported source, absent or ambiguous locator, malformed artifact, over-bound input, permission or step drift, invalid recovery actor or target, provider failure, queue exhaustion, replay, or unstable reread produces no lifecycle effect and requires a later independent event, scheduled scan, or new explicit authorized recovery. A delayed or dropped scheduled run produces no false success and waits for a later successful scan or another allowed event.
  • Platform variants: Hermetic workflow-contract tests run on macOS and Ubuntu; live guarded-off proof uses disposable GitHub metadata and never mutates lifecycle state or dev.
  • Evidence produced consistently for every affected option: Caller workflow/ref/SHA, reusable callee workflow/ref/SHA, referenced-workflow metadata, run and attempt, exact resolver subtype and permissions, locator identity and counter values, per-issue group, provider-budget group, outcome class, and sanitized provider status.

Options

Option Description Expected benefit Cost or risk Rejection condition
A — Protected caller plus reusable coordinator One protected top-level wake workflow resolves typed read-only locators; its per-issue coordinate job invokes the sole reusable coordinator and authenticates both caller and callee No Actions write or added identity; preserves one writer, exact issue serialization, and provider-native evidence Reviews rely on nominal hourly scans that GitHub may delay or drop; there is no bounded review latency and the source/permission/boundary matrix must remain closed Reject if GitHub cannot prove both identities at one protected dev SHA or cannot hold the caller job lock for the callee duration
B — Workflow dispatch router A protected router dispatches a new top-level coordinator run using actions: write Makes the coordinator the primary run identity Coarse permission can cancel, rerun, enable, disable, or delete workflow evidence and violates least privilege Rejected by independent v2 threat-model audit
C — Relax authentication or add a dedicated identity/service Trust caller metadata less strictly or introduce an App, machine user, PAT, broker, database, or hosted service Could separate transport and writer operationally Weakens accepted proof or violates the no-additional-identity and operational boundary Reject because Option A satisfies the boundary with existing GitHub-native primitives

Evaluation plan

  • Method: Primary-source compatibility research, actual-run metadata inspection, OIDC claim analysis, threat-model evaluation, hermetic workflow-contract tests, and guarded-off disposable GitHub proof.
  • Time or scope box: One immutable ADR-0012 and consistent vNext planning contracts. No lifecycle activation, issue/status mutation by implementation code, branch/PR/queue/merge effect, repository administration, or productive workflow implementation.
  • Workloads, scenarios, or attack paths: Every closed direct event subtype; every closed workflow-run source; review/conversation schedule liveness; duplicate and reordered wakes; forged issue/repository/ref/caller/callee; caller-selected policy fields; missing, extra, stale, duplicated, oversized, or malformed locator artifacts; 64/65,536/512-byte boundaries; page two/three; locator 200/201; request ceilings 0/2/4/6/8 and first excess; permission and step drift; artifact runtime credentials; Actions recursion suppression; OIDC or referenced-workflow mismatch; API 403/404/409/422/429/timeout/malformed; queue full; cancellation; replay; created/update equality, non-null lastEditedAt, non-null editor, and true includesCreatedEdit; restored edited bodies; direct comment-ID substitution, deletion, and unstable reread; duplicate, reordered, and replayed commands; an already consumed target; normal-window page two and first candidate outside the bounded window; an older non-allowlisted or permission-revoked command before a later valid command; zero/one/two/three distinct allowlisted actors; permission-prefilter request four/five; lowest-ID selection only after the complete prefilter; more than one selected candidate per invocation; every producer wire input's exact position, GitHub string primitive, canonical null/producer-version/positive-ID and non-negative-attempt decimal/commit/target-branch/base64/digest/producer encoding, the first .. and component-ending-.lock target complements, 512/65,536-byte boundary and first excess, missing/extra/reordered/wrong-primitive input, invalid base64, decoded-empty generation, re-encoding mismatch, and digest mismatch; and credential-shaped input.
  • Metrics, thresholds, and measurement method: Zero actions: write; exactly one protected caller path, one reusable coordinator path, and the closed two-path reusable producer set; caller, coordinator, and producer at the same protected dev SHA; exact source/event/permission tables above; zero authority-bearing locator fields; zero resolver writes; exact numeric bounds; every provider-reading resolver holding only the provider-budget group; exact per-issue caller lock before every coordinator or producer provider job; exact provider-budget lock second for that nested chain; one exact ordered string-only producer wire schema with the closed producer-to-version mapping and canonical null/decimal/commit/target-branch/base64/digest/producer encodings, including rejection of .. and component-ending-.lock targets and 512/65,536-byte bounds; one exact allowlisted-maintainer recovery comment with a stable numeric locator, stable actor, live permission, equal creation/update timestamps, null last-edit/editor values, false creation-edit flag, exact target double-read, domain-separated authorized-request identity, at-most-once target consumption, two-actor/four-request permission prefilter, one-candidate-per-invocation bounded fallback, no unauthorized-candidate starvation, and no history-wide scan; complete coordinator and producer reload; and zero success after any authority mismatch.
  • Reference hardware, operating systems, versions, and dependencies: Current protected dev, GitHub.com Actions/REST/GraphQL and artifact attestations, macOS, GitHub-hosted Ubuntu, Node.js 24.18.x, npm 11.16.x, and repository-owned harnesses.
  • Required primary sources and repository evidence: GitHub reusable-workflow identity and permission inheritance, OIDC reusable-workflow claims, event ref/SHA tables, check_run recursion suppression, workflow_run behavior, issue-comment creation/update/last-edit fields and pagination, artifact and workflow-run APIs, 256-job matrix limit, job-level concurrency for reusable calls, actual run 30393476770, accepted ADR-0011, Protected lifecycle request ingress and activated event wiring #51's negative reusable-caller fixture, and the independent audits.
  • Reproduction commands and retained artifacts: npm ci --ignore-scripts, node --test quality/contract.test.mjs, focused lifecycle/wakeup/authentication/boundary tests, npm run quality, and npm audit --audit-level=high; retain ADR text, sanitized fixtures, run metadata, and independent audit evidence only.
  • Testability, automation harness, CI ownership, and production-artifact isolation: Repository-owned Node tests and protected workflows own the harness. Locator artifacts are bounded body-free operational metadata with no product or release-artifact inclusion. No experimental productive code is authorized.
  • Bias, uncertainty, and evidence limitations: Option A remains selected after successive independent audit rounds changed its exact source, trust topology, and recovery proof. GitHub's provider behavior is external; failure of the guarded-off live proof leaves lifecycle activation disabled. Review and conversation changes have no bounded latency: GitHub may delay or drop nominal hourly runs, and recovery waits for a later successful scan or another allowed event.

Existing uncommitted #51 work remains salvageable implementation evidence only and must not be committed or published until ADR-0012 is accepted and the affected contracts regain fresh readiness.

Execution Authority

The repository-wide defaults in AGENTS.md apply and are not repeated here.

  • Authorized repository: oscharko-dev/Keiko-Native.
  • Exact delivery target: dev
  • Allowed write scope: docs/adr/ADR-0012-*.md, docs/adr/README.md, affected governance documentation and contract tests, plus issue/PR metadata required for this decision. Existing accepted ADRs are read-only.
  • Additional prohibited paths or actions: No productive workflow implementation, product source, dependency/lockfile, activation enablement, live lifecycle/status/check/content/branch/pull-request/queue/merge mutation by implementation code, repository administration, external identity/service, or credential inspection.
  • Authorized external mutations: Revise this decision and affected planning records, request readiness, create one dedicated source branch and pull request targeting dev, and record sanitized evidence. No merge, auto-merge, enqueue, or repository administration is authorized.
  • Required credentials or secrets: Existing authenticated GitHub metadata/publication access only; no token may be inspected, copied, persisted, or emitted.
  • Delivery authority: Human-only manual merge to dev.
  • Additional stop or escalation conditions: Stop if the design needs actions: write, any new identity or service, any unlisted source/event/resolver permission, any authority-bearing locator, a caller/coordinator/producer SHA mismatch, a non-reusable producer start, a second lifecycle writer, unauthenticated recovery, reversed nested lock order, weakened record authentication, changed numeric bound, schedule liveness or failure model, or any automated dev action.

Decision matrix

Criterion Weight Option A Option B Option C Evidence
Protected writer identity and exact serialization 30 5 5 3 Actual caller/callee run metadata, OIDC claims, and job-concurrency contract
Least privilege and evidence durability 25 5 1 3 REST permission surface, artifact runtime boundary, and ADR-0011 evidence threat model
No added identity, secret, or hosted dependency 20 5 5 1 Existing built-in Actions identity and repository-owned workflow composition
Deterministic recovery and auditability 15 4 3 4 Locator rejection, scheduled review liveness, exact-comment authentication, target idempotency, complete reload, fencing, and record-chain rules
Operational simplicity 10 4 4 1 Protected workflow and maintenance analysis
Weighted total 100 4.75 3.70 2.50 Option A satisfies every non-negotiable without the rejected coarse capability

Acceptance criteria

  • AC1 — ADR-0012 records the actual reusable-workflow identity, event ref/SHA, recursion, artifact-runtime, and permission evidence; selects Option A; and preserves ADR-0011 v1 record schemas, the sole coordinator, the closed producer ownership and result names, all nine lifecycle states, and human-only dev.
  • AC2 — The ADR freezes the exact protected caller/reusable-coordinator/nested-producer chain, complete ordered string-only producer wire inputs, the closed producer-to-version mapping, the self-contained canonical target grammar, .. and component-ending-.lock exclusions, and byte-exact authority checks, and all other canonical encodings, direct event and workflow-run source tables, five minimum-permission resolver profiles, exact numeric bounds, no-actions: write and no-artifact-write resolver structure, provider-budget-only serialization for provider-reading resolvers, caller-held per-issue lock, nested provider-budget lock second, scheduled review liveness, and independent authority reload.
  • AC3 — Record authentication binds .github/workflows/lifecycle-wakeup.yml, ./.github/workflows/issue-lifecycle.yml, and the exact closed producer path at the same protected dev SHA through run metadata, the complete referenced-workflow chain, OIDC claims, artifact anchor, and attestation verification; REST head_sha, event/source locators, recovery event payloads, and producer conclusions grant no authority; every mismatch fails closed without changing v1 record fields.
  • AC4 — Explicit forward recovery is reachable only through an exact never-edited issue-comment command from the repository-owned maintainer allowlist with independently verified numeric actor identity and live maintain or admin permission. The direct wake supplies only typed issue and comment-ID locators; the locked coordinator double-fetches that exact comment and requires stable body, actor, target, creation/update equality, null last-edit/editor values, and false creation-edit flag. A domain-separated authorized-request identity binds repository, issue, comment, body digest, creation time, actor, and target through ADR-0011's existing version-1 request field. At most one authenticated recovery record consumes each target, making duplicate or reordered commands replay no-ops. Other wakes inspect only the stable two-page normal window, prefilter exact never-edited commands through immutable allowlist membership and two stable live-permission reads for each of at most two actors, then process at most one deterministic lowest-ID eligible candidate. Non-allowlisted and permission-revoked commands cannot starve a later valid candidate. The fallback never performs history-wide or cursor-resumed command discovery.
  • AC5 — Epic Epic: Contract-as-Code migration and lifecycle activation cutover (ADR-0003/ADR-0004) #49, issue Protected lifecycle request ingress and activated event wiring #51, and issue Signed activation switch, in-flight continuity, and integrated acceptance #55 increment contract versions, remain status: new until ADR-0012 is human-merged, then cite it and obtain fresh readiness; Guarded agent epic-merge controls and repository probes #50, Exact migration inventory, one-time reconciliation, and activation orchestration #52, Terminal migration manifest publication under legacy authority #53, and Manifest-bound Contract-as-Code candidate publication #54 remain unchanged.

Verification commands

git diff --check origin/dev..HEAD
npm ci --ignore-scripts
node --test quality/contract.test.mjs
npm run quality
npm audit --audit-level=high

Definition of Ready

  • The decision question, owner, urgency, constraints, options, and non-goals are explicit.
  • Evaluation methods, equal-workload criteria, thresholds, environments, and evidence sources are defined before results are collected.
  • Execution Authority and experimental-code disposal are explicit.
  • The governance-only evaluation is executable without adding an identity, secret, service, or unauthorized effect.

Definition of Done

  • Every criterion has attributable, reproducible evidence and recorded limitations.
  • The recommendation, dissenting evidence, risks, and residual uncertainty are explicit.
  • ADR-0012 is accepted through a human-only protected-dev merge without modifying prior accepted ADRs.
  • Epic Epic: Contract-as-Code migration and lifecycle activation cutover (ADR-0003/ADR-0004) #49 and affected child contracts reflect the selected transport consistently.
  • No throwaway code, secret, private evidence, added identity, or undeclared dependency remains.

Stop conditions

  • Stop when the current contract version does not match its automated readiness record.
  • Stop if any option, criterion, weight, direct event, workflow-run source, resolver permission, numeric bound, caller/callee identity, producer input name/order/primitive/encoding, positive-ID or non-negative-attempt decimal domain, producer-to-version mapping, target grammar or byte-equality rule, locator schema, recovery edit predicate, authorized-request identity, target-consumption or bounded-fallback rule, lock order, lifecycle ownership, or delivery authority changes.
  • Stop if caller and callee cannot be proven at the same protected dev SHA, if REST head_sha or a source/locator value grants authority, if locator resolution performs an authority read or repository write, if any caller value bypasses coordinator reload, or if a credential could enter evidence.
  • Stop before merging the decision pull request; dev remains a deliberate human action.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

status: readyReady for implementationtype: decisionEvidence-backed architecture, product, security, or platform decision

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions