Kernel: a Lens run by GitHub Actions is read only from its own workflow file
Part of the epic "Epic: slice 0, foundations. The repo holds the line, its context is tested, and the platform facts are recorded". Part of #97: its third item, the main ruleset pinning each required check's App, is the Maintainer's in GitHub and stays with "The Factory repo's rulesets hold the Release tags and each required check's App" (#62).
"Kernel: a Lens is read only from the App that reports it" (#98) pinned each required Lens to its App. GitHub Actions is one App (15368) for every job in the repo, including one a pull request adds on its own branch with the same name.
The rule
facts.checks[].workflowis the workflow file of the run that made the check (the port reads it from the check suite's workflow run, verbatim, or null). Each entry ofrequired_lenses.deterministicnames itsworkflow:.github/workflows/verify.ymlforverify,.github/workflows/ci.ymlforSecret scan (gitleaks), null forCodeQL(App 57789, run by no workflow).- A check matches a Lens only by its name, App and workflow. One under a Lens's name from another workflow file, or with no workflow where the Lens names one, is
check_unreadable, read before any Lens's failure; a queued item leaves the queue; it moves nothing (#94). - The evidence is
<lens>:from_workflow:<path>only when the path has the configuration's form (.github/workflows/<name>.yml|yaml, ASCII, at mostlimits.max_path_length), and…:from_workflow:unreadableotherwise, so no outside text reaches a Decision. tools/check_workflows.pyholds the configuration to the files: a Lens run by Actions names a workflow and no other does; the file exists and runs a job under the Lens's check name (itsjobs.<id>.name, or its id), onpull_requestandmerge_group, with no matrix, job-levelif:oruses:.
What the pin does not hold
The pin holds the workflow file's path, not its content or what it runs. A pull request from a branch of this repo, or a Dependabot security update (class dependency, no model review), can edit .github/workflows/verify.yml in place and still report from that path; verify runs the pull request's own Makefile, tools/ and tests/, and the secret scan reads its .gitleaks.toml. What holds .github/ today: no Factory App holds workflows (now checked by tools/check_apps.py), so GitHub refuses an App's push there; fork admission (I-36); apply for Roles, waiting on harness/; and the session hooks, locally. The main ruleset requires no review and pins only verify. The gap is "Kernel: a change to the Factory's own rules or a Lens's inputs needs a person" (#113).
Recorded, unverified
Trial P-35 asks whether a check run names the workflow that ran it, in what form, whether CodeQL's has none, and where a check run created through the API with checks: write lands. Trial P-36 asks whether an upload to code scanning under CodeQL's tool and category can replace its verdict; no Factory App holds security_events (checked), and the workflow lint now refuses a job-level security-events: write.
Decision
docs/decisions/0018-a-lens-is-read-from-its-own-app-and-workflow-and-only-what-gates-holds-a-merge.md replaces 0015, whose Status says so; decision 0005 changes a Check cell only.
Tests
test_a_check_from_another_workflow_is_unreadable_for_its_lens, test_a_check_from_another_workflow_takes_it_out_of_the_queue, test_only_a_check_from_its_lens_workflow_moves_an_item, test_a_workflow_path_is_shown_only_in_its_form; in tests/test_tools.py the Lens-to-workflow rules and test_no_app_may_change_a_workflow_or_upload_to_code_scanning. The simulator posts a passing check from .github/workflows/impostor.yml under a Lens's own App, and the seeds reach both from_app and from_workflow evidence. A corpus of 27,277 decisions recorded on main replays identically with the fields filled; 303 of 303 mutants killed.
Read by
A fresh-context review, a separate security pass (Claude) and AGY (Gemini 4 Argon), on the first commits; the last commit answers them. About 190 probes found no check from another App or workflow that lets an item converge, be approved or stay queued. make verify passes in a worktree and on a git archive export (477 tests). AGY (Gemini 4 Argon) read the final head, 6e94d04, and found no defects.
🤖 Generated with Claude Code
Summary by CodeRabbit
- New Features
- Required checks can now be tied to a specific workflow file. Checks from a different workflow, or without usable workflow information, are treated as unreadable and cannot satisfy the requirement.
- Workflow validation now checks that configured workflows exist, run for pull requests and merge groups, and contain the expected check.
- Bug Fixes
- Workflows with permissions that could undermine check verification are rejected.