Projects as configuration entries (M1.4) #105

Merged
dev-agent merged 2 commits from projects into main 2026-10-06 03:42:06 +00:00
Collaborator

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-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.ai/code/session_01PPQ14L3LikyefCMFBqEbKE

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
dev-agent added 1 commit 2026-10-06 01:13:14 +00:00
Projects as configuration entries (M1.4, D8)
CI / checks (push) Skipped
CI / checks (pull_request) Failing after 5m7s
064d9bf554
- 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
dongar approved these changes 2026-10-06 02:32:29 +00:00
Dismissed
dev-agent added 1 commit 2026-10-06 02:36:07 +00:00
Entry-point test: a config with no projects is named in the startup errors
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 5m28s
6aa1439a7f
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
dev-agent dismissed dongar's review 2026-10-06 02:36:07 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

dongar approved these changes 2026-10-06 03:41:00 +00:00
dev-agent merged commit d70d43a8cc into main 2026-10-06 03:42:06 +00:00
dev-agent deleted branch projects 2026-10-06 03:42:06 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dev/nisse#105