M1.4 of the Development Plan (D8). The acceptance: the bring-up configuration is one project entry, and a second project needs only a second entry.
Configuration
projects:demo:repo:owner/demo-repobase_branch:mainworkspace:/root/work/demo # on the build VMbuild_host:{address:build-demo.example, key:~/.ssh/nisse-dev}push_key:~/.ssh/push-demo-repolabels:[discuss] # added to every issue's ownsecrets:DATABASE_URL:{value:"${DEMO_DATABASE_URL}", visible:commands}egress:[pypi.org] # recorded, not yet enforced
The flat project, workspace, build_host, gitea.repo, gitea.base_branch and gitea.push_* keys are gone.
Every problem in every entry is reported at once. These are errors:
an unknown key or a missing repo;
a repo used by two projects;
a project name that isn't a slug;
a secret written inline rather than as ${VAR};
a visibility other than commands or harness.
The example config, nisse-test.yaml and the config tests are converted.
Bring-up (outside the repo): the converted config is ready at /root/nisse-e2e/nisse-dev.yaml.m1.4. The running bring-up agent, whose code snapshot dates from Oct 3, still uses the old file, so a restart can't break it. I'll swap the files when the bring-up is redeployed.
The loops
The old loop (control.py, until M2.8) runs exactly one project, through config.only_project(), and refuses more.
The new loop is per project.
Setup: each project gets its own clone, workspace, push credential and milestones. The workspace receives that project's commands secrets as run_command environment variables, redacted from output.
Running: intake polls every project's repository, and every run, publish and PR watch goes through the item's own project.
Naming: with more than one project, items are named alpha#14. A bare #14 that matches two items is asked about ("say go alpha#14 or go beta#14"); the same goes for "do #14 next".
Switching projects parks the workspace of the project worked on last. After a boot nobody knows which that was, so every other project is parked.
Label defaults steer as if the issue carried them.
Also in this PR: restatements that ask
On this branch the e2e plain-yes test failed again. The test config's driver (Haiku) ended every restatement with "Is this the right interpretation?", despite the prompt line from #102, and a plain yes can't answer that, so the reader was right to refuse. The fix is structural: Driver.run takes checks for waiting tools, and a restatement ending in a question is sent back to the driver ("not posted: a restatement asks no questions… use ask_human") instead of being posted.
Tests
Config: entries, defaults and every error above, plus the old loop's refusal of two projects.
Assembly: two projects get two clones, their own labels and their own secrets.
test_loop_projects.py:
#14 in both projects is told apart;
each item works and publishes in its own project;
a bare #14 is asked about, and so is "do #14 next";
label defaults steer;
switching projects parks the other project's half-done work.
The property walk over two projects (16 seeds, colliding issue numbers):
new property own_repository_only; making every item use the first project fails 15 of 16 seeds;
the other properties now run per project.
E2E: the suite runs on the single-entry test config. Full run: 6 of 6 after the restatement check; plain-yes also passed twice on its own.
Deferred
Config reload without a restart (with M2.5's entry step, if wanted).
Egress enforcement (D7), handing harness secrets to anything, and the trust dial's configuration (M3.3).
M1.4 of the Development Plan (D8). The acceptance: the bring-up configuration is one project entry, and a second project needs only a second entry.
## Configuration
```yaml
projects:
demo:
repo: owner/demo-repo
base_branch: main
workspace: /root/work/demo # on the build VM
build_host: {address: build-demo.example, key: ~/.ssh/nisse-dev}
push_key: ~/.ssh/push-demo-repo
labels: [discuss] # added to every issue's own
secrets:
DATABASE_URL: {value: "${DEMO_DATABASE_URL}", visible: commands}
egress: [pypi.org] # recorded, not yet enforced
```
- The flat `project`, `workspace`, `build_host`, `gitea.repo`, `gitea.base_branch` and `gitea.push_*` keys are gone.
- Every problem in every entry is reported at once. These are errors:
- an unknown key or a missing `repo`;
- a repo used by two projects;
- a project name that isn't a slug;
- a secret written inline rather than as `${VAR}`;
- a visibility other than `commands` or `harness`.
- The example config, `nisse-test.yaml` and the config tests are converted.
- **Bring-up (outside the repo):** the converted config is ready at `/root/nisse-e2e/nisse-dev.yaml.m1.4`. The running bring-up agent, whose code snapshot dates from Oct 3, still uses the old file, so a restart can't break it. I'll swap the files when the bring-up is redeployed.
## The loops
- **The old loop** (`control.py`, until M2.8) runs exactly one project, through `config.only_project()`, and refuses more.
- **The new loop** is per project.
- **Setup:** each project gets its own clone, workspace, push credential and milestones. The workspace receives that project's `commands` secrets as `run_command` environment variables, redacted from output.
- **Running:** intake polls every project's repository, and every run, publish and PR watch goes through the item's own project.
- **Naming:** with more than one project, items are named `alpha#14`. A bare `#14` that matches two items is asked about ("say go alpha#14 or go beta#14"); the same goes for "do #14 next".
- **Switching projects** parks the workspace of the project worked on last. After a boot nobody knows which that was, so every other project is parked.
- **Label defaults** steer as if the issue carried them.
## Also in this PR: restatements that ask
On this branch the e2e plain-yes test failed again. The test config's driver (Haiku) ended every restatement with "Is this the right interpretation?", despite the prompt line from #102, and a plain yes can't answer that, so the reader was right to refuse. The fix is structural: `Driver.run` takes `checks` for waiting tools, and a restatement ending in a question is sent back to the driver ("not posted: a restatement asks no questions… use ask_human") instead of being posted.
## Tests
- **Config:** entries, defaults and every error above, plus the old loop's refusal of two projects.
- **Assembly:** two projects get two clones, their own labels and their own secrets.
- **`test_loop_projects.py`:**
- `#14` in both projects is told apart;
- each item works and publishes in its own project;
- a bare `#14` is asked about, and so is "do #14 next";
- label defaults steer;
- switching projects parks the other project's half-done work.
- **The property walk over two projects** (16 seeds, colliding issue numbers):
- new property `own_repository_only`; making every item use the first project fails 15 of 16 seeds;
- the other properties now run per project.
- **E2E:** the suite runs on the single-entry test config. Full run: 6 of 6 after the restatement check; plain-yes also passed twice on its own.
## Deferred
- Config reload without a restart (with M2.5's entry step, if wanted).
- Egress enforcement (D7), handing `harness` secrets to anything, and the trust dial's configuration (M3.3).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
- Config: `projects: {name: entry}` with repo, base_branch, workspace,
build_host, push credential, labels (defaults added to every issue),
secrets by ${VAR} reference with visibility (commands | harness), and
egress (recorded, not enforced). Every problem in every entry is
reported at once; an inline secret, a bad visibility, a repeated repo or
a non-slug name is an error.
- The old loop runs exactly one project (only_project) and refuses more.
- The new loop is per project: each its own clone, workspace (with its
commands-visible secrets, redacted on return), push credential and
milestones; intake polls every project's repository; items are scoped
to their project for every run, publish and PR watch. Issues are named
project#14 when there is more than one project, and a bare #14 that
matches two is asked about. Switching projects parks the one worked on
last (all others after a boot).
- A restatement that ends in a question is sent back to the driver, not
posted: the e2e driver kept asking "Is this the right interpretation?",
which a plain yes can't answer.
Tests: config entries and errors, two-project assembly, two-project loop
tests (intake, own workspaces and repos, #14 in both, do-next, label
defaults, parking across projects), the property walk over two projects
with a new own_repository_only property (an item using the first
project's repo fails 15 of 16 seeds), and the restatement check.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
M1.4 of the Development Plan (D8). The acceptance: the bring-up configuration is one project entry, and a second project needs only a second entry.
Configuration
project,workspace,build_host,gitea.repo,gitea.base_branchandgitea.push_*keys are gone.repo;${VAR};commandsorharness.nisse-test.yamland the config tests are converted./root/nisse-e2e/nisse-dev.yaml.m1.4. The running bring-up agent, whose code snapshot dates from Oct 3, still uses the old file, so a restart can't break it. I'll swap the files when the bring-up is redeployed.The loops
control.py, until M2.8) runs exactly one project, throughconfig.only_project(), and refuses more.commandssecrets asrun_commandenvironment variables, redacted from output.alpha#14. A bare#14that matches two items is asked about ("say go alpha#14 or go beta#14"); the same goes for "do #14 next".Also in this PR: restatements that ask
On this branch the e2e plain-yes test failed again. The test config's driver (Haiku) ended every restatement with "Is this the right interpretation?", despite the prompt line from #102, and a plain yes can't answer that, so the reader was right to refuse. The fix is structural:
Driver.runtakeschecksfor waiting tools, and a restatement ending in a question is sent back to the driver ("not posted: a restatement asks no questions… use ask_human") instead of being posted.Tests
test_loop_projects.py:#14in both projects is told apart;#14is asked about, and so is "do #14 next";own_repository_only; making every item use the first project fails 15 of 16 seeds;Deferred
harnesssecrets to anything, and the trust dial's configuration (M3.3).🤖 Generated with Claude Code
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
- Config: `projects: {name: entry}` with repo, base_branch, workspace, build_host, push credential, labels (defaults added to every issue), secrets by ${VAR} reference with visibility (commands | harness), and egress (recorded, not enforced). Every problem in every entry is reported at once; an inline secret, a bad visibility, a repeated repo or a non-slug name is an error. - The old loop runs exactly one project (only_project) and refuses more. - The new loop is per project: each its own clone, workspace (with its commands-visible secrets, redacted on return), push credential and milestones; intake polls every project's repository; items are scoped to their project for every run, publish and PR watch. Issues are named project#14 when there is more than one project, and a bare #14 that matches two is asked about. Switching projects parks the one worked on last (all others after a boot). - A restatement that ends in a question is sent back to the driver, not posted: the e2e driver kept asking "Is this the right interpretation?", which a plain yes can't answer. Tests: config entries and errors, two-project assembly, two-project loop tests (intake, own workspaces and repos, #14 in both, do-next, label defaults, parking across projects), the property walk over two projects with a new own_repository_only property (an item using the first project's repo fails 15 of 16 seeds), and the restatement check. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKENew commits pushed, approval review dismissed automatically according to repository settings