Plan MIL-008: the local project has origin as its only remote

A project created by the script had two remotes, origin (Gitea) and github.
Gitea already pushes to GitHub through the push mirror, so the second remote
is not needed and invites a push that goes around the mirror.

- MIL-008 and its review record RC-031
- Objective 4, US-001.03, UC-001 step 8, OC-001 P9, SD-001, DCD-001, DCD-002,
  DM-001 and DM-002 describe one remote; MIL-003 criterion 1 and task 1 follow
- Project plan and traceability matrix list MIL-008 and RC-031
This commit is contained in:
2026-10-08 11:13:09 +08:00
parent f64c4bd2f0
commit 039a28c01b
15 changed files with 224 additions and 68 deletions
+5 -6
View File
@@ -9,8 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-06 | Deprecated | Jens Tirsvad Nielsen | S02 | ProjectRequest carries the license that applies | [d773fa9] |
| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S02 | Note that DCD-003 and DCD-002 supersede the signature of startProjectCreation | [0b0a3b4] |
| 2026-10-08 | Proposed | Jens Tirsvad Nielsen | S02 | LocalProjectBuilder.build() no longer takes the GitHub repository; a Local Project has one Remote, origin (MIL-008) | pending |
---
@@ -75,7 +75,7 @@ class GitHubClient <<facade>> {
+createEmptyRepository(request : ProjectRequest) : GitHubRepository
}
class LocalProjectBuilder {
+build(directory : Path, source : GiteaRepository, target : GitHubRepository [0..1], sshPassed : Boolean) : LocalProject
+build(directory : Path, source : GiteaRepository, sshPassed : Boolean) : LocalProject
}
class FrameworkInstaller {
+install(project : LocalProject, enablePlanGate : Boolean) : InstallResult
@@ -215,7 +215,7 @@ PushMirror "0..*" --> "1" GiteaRepository : source
PushMirror "0..*" --> "1" GitHubRepository : target
PushMirror "0..*" --> "1" Credential : authorised by
LocalProject "1" *-- "1..2" Remote
LocalProject "1" *-- "1" Remote
Remote "0..*" --> "1" Repository : points to
LocalProject "1" *-- "1" Submodule
LocalProject "1" *-- "1" HookSetup
@@ -261,7 +261,7 @@ Repository "0..*" --> "1" Visibility
| `LicenseFile` | License | The license file in the Gitea repository when a license applies. | `key` | none |
| `PushMirror` | Mirror | The Gitea to GitHub push mirror. | `interval`, `syncOnCommit` | none |
| `LocalProject` | Local Project | The project directory on the Maintainer's machine. | `directory` | none |
| `Remote` | Remote | A named link to a repository (`origin`, `github`), without a credential. | `name`, `address` | none |
| `Remote` | Remote | A named link to a repository (`origin`), without a credential. | `name`, `address` | none |
| `Submodule` | Framework | The framework added to the local project. | `name`, `address` | none |
| `HookSetup` | Framework Setup | Records the skills and hooks installed and the plan gate state. | `areSkillsInstalled`, `areHooksInstalled`, `isPlanGateEnabled` | none |
| `EnvFile` | Credentials File | The `.env` of the project: a copy of the credentials it needs. | `address`, `keys` | none |
@@ -291,7 +291,7 @@ Repository "0..*" --> "1" Visibility
| `GiteaClient.requestSync(mirror) : void` | [SD-001] `requestSync(pushMirror)`; P6 |
| `GitHubClient(configuration)` | [SD-001] `new(configuration)` to `GitHubClient` |
| `GitHubClient.createEmptyRepository(request) : GitHubRepository` | [SD-001] `createEmptyRepository(request)`; P5 |
| `LocalProjectBuilder.build(directory, source, target, sshPassed) : LocalProject` | [SD-001] `build(directory, giteaRepository, gitHubRepository, sshPassed)`; P7, P8, P9 |
| `LocalProjectBuilder.build(directory, source, sshPassed) : LocalProject` | [SD-001] `build(directory, giteaRepository, sshPassed)`; P7, P8, P9 |
| `FrameworkInstaller.install(project, enablePlanGate) : InstallResult` | [SD-001] `install(localProject, enablePlanGate)`; P10, P11, P12 |
| `SummaryReport.compose(request) : Summary` | [SD-001] `compose(projectRequest)`; P13 |
@@ -339,7 +339,6 @@ SOLID check: no class has more than one reason to change (one host API, one kind
[MIL-005]: ../milestones/mil-005-credentials.md
[DICT-001]: ../dictionary.md
[DCD-002]: ../dcd.md
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
[DCD-003]: ../uc-002/dcd.md
[UC-002]: ../uc-002/uc.md
[0b0a3b4]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/0b0a3b419a1157b23bddd2f8957a08adaf6974a6
+4 -5
View File
@@ -9,8 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-06 | Proposed | Jens Tirsvad Nielsen | S02 | License applies when configured, not only when GitHub is chosen | [d773fa9] |
| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S02 | License: the AGPL-3.0 default needs GitHub and a public project | [1cd27f7] |
| 2026-10-08 | Proposed | Jens Tirsvad Nielsen | S02 | A Local Project has one Remote, origin, no longer one or two (MIL-008) | pending |
---
@@ -104,7 +104,7 @@ Mirror "1" --> "1" GiteaRepository : copies from
Mirror "1" --> "1" GitHubRepository : copies to
Mirror "0..*" --> "1" AccessToken : is authorised by
LocalProject "1" --> "1" Project : is the working copy of
LocalProject "1" --> "1..2" Remote : has
LocalProject "1" --> "1" Remote : has
Remote "0..*" --> "1" Repository : points to
LocalProject "1" --> "1" Framework : includes
LocalProject "1" --> "1" FrameworkSetup : has
@@ -133,7 +133,7 @@ Summary "1" --> "1" Project : reports on
| License | The legal terms file added to a Gitea Repository when a license applies: the one set in the Configuration, or AGPL-3.0 when GitHub is chosen, the project is public and none is set | name | [UC-001] step 6 "license" |
| Mirror | The push mirror that copies a Gitea Repository to a GitHub Repository | interval, sync on commit | [UC-001] step 7 "push mirror" |
| Local Project | The project directory on the Maintainer's machine | directory | [UC-001] step 8 "local project" |
| Remote | A named link from a Local Project to a Repository (`origin`, `github`) | name, address | [UC-001] step 8 "remote" |
| Remote | A named link from a Local Project to a Repository (`origin`) | name, address | [UC-001] step 8 "remote" |
| Framework | The SQA-QC-Framework added to a Local Project | name, address | [UC-001] step 9 "framework submodule" |
| Framework Setup | The skills and git hooks installed from the Framework, with the plan gate on or off | plan gate enabled | [UC-001] step 9 "skills and hooks", "plan gate" |
| Template | A file the Framework provides to copy into a project (`AGENTS.md`, artifact registry) | name | [UC-001] step 9 "templates" |
@@ -157,7 +157,7 @@ Summary "1" --> "1" Project : reports on
| Mirror | copies to | GitHub Repository | 1 to 1 |
| Mirror | is authorised by | Access Token | 0..* to 1 |
| Local Project | is the working copy of | Project | 1 to 1 |
| Local Project | has | Remote | 1 to 1..2 |
| Local Project | has | Remote | 1 to 1 |
| Remote | points to | Repository | 0..* to 1 |
| Local Project | includes | Framework | 1 to 1 |
| Local Project | has | Framework Setup | 1 to 1 |
@@ -180,5 +180,4 @@ Summary "1" --> "1" Project : reports on
[SSD-001]: ./ssd.md
[DICT-001]: ../dictionary.md
[DM-002]: ../domain-model.md
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
[1cd27f7]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/1cd27f77ed844773a969210a11de0d8bb98ac98f
+2 -3
View File
@@ -9,8 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S02 | P4: the AGPL-3.0 default needs githubOwner and a public visibility; P10: the framework's own submodules were initialised, with an exception for a failed fetch | [1cd27f7] |
| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S02 | Note that OC-002 and DCD-002 supersede the signature of startProjectCreation | [0b0a3b4] |
| 2026-10-08 | Proposed | Jens Tirsvad Nielsen | S02 | P9: no other remote is associated with the local project (MIL-008) | pending |
---
@@ -71,7 +71,7 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-001]. `
- P6. If `githubOwner` is present, a `PushMirror` instance was created, associated with the `GiteaRepository` as source and the `GitHubRepository` as target, with its effective sync setting recorded, and a first sync was requested.
- P7. A `LocalProject` instance was created at `directory`, associated with the `ProjectRequest`. If the `GiteaRepository` is not empty, the `LocalProject` holds its history, including the `LicenseFile` commit.
- P8. A `Remote` named `origin` was associated with the `LocalProject`, pointing at the `GiteaRepository` over SSH if the SSH test passed, otherwise over HTTPS, with no credential in its URL.
- P9. If `githubOwner` is present, a `Remote` named `github` was associated with the `LocalProject`, pointing at the `GitHubRepository`, with no credential in its URL.
- P9. No other `Remote` was associated with the `LocalProject`, whether or not `githubOwner` is present: the `GitHubRepository`, when there is one, is reached through the `PushMirror` of P6, not through a remote.
- P10. A `Submodule` named `framework` was associated with the `LocalProject`, and the submodules the framework itself holds (`qc`) were initialised.
- P11. A `HookSetup` instance was associated with the `LocalProject`, recording that skills and git hooks were installed once and, if `enablePlanGate`, that the plan gate was enabled.
- P12. `AGENTS.md` and `docs/artifact-registry.md` exist in the `LocalProject`, each either newly copied from the framework templates or left as it was because the Maintainer declined to replace it.
@@ -98,7 +98,6 @@ Concepts below use the IT terms of [DICT-001] for the PO concepts of [DM-001]. `
[DM-001]: ./dm.md
[DICT-001]: ../dictionary.md
[SD-001]: ./sd.md
[1cd27f7]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/1cd27f77ed844773a969210a11de0d8bb98ac98f
[OC-002]: ../uc-002/oc.md
[DCD-002]: ../dcd.md
[UC-002]: ../uc-002/uc.md
+4 -5
View File
@@ -9,8 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S02 | P4: the license passed is AGPL-3.0 only for GitHub with a public project | [1cd27f7] |
| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S02 | Note that SD-002 and DCD-002 supersede the signature of startProjectCreation | [0b0a3b4] |
| 2026-10-08 | Proposed | Jens Tirsvad Nielsen | S02 | build() no longer receives the GitHub repository and returns a local project with the remote origin; P9 (MIL-008) | pending |
---
@@ -146,9 +146,9 @@ opt githubOwner present
end
create LB
PC -> LB : build(directory, giteaRepository, gitHubRepository, sshPassed)
PC -> LB : build(directory, giteaRepository, sshPassed)
activate LB
LB --> PC : localProject (remotes origin, github)
LB --> PC : localProject (remote origin)
deactivate LB
create FI
@@ -203,7 +203,7 @@ destroy SR
| P6 PushMirror and first sync | `addPushMirror(...)` and `requestSync(pushMirror)` |
| P7 LocalProject created, history from Gitea when not empty | `build(directory, ...)` |
| P8 origin remote (SSH if the test passed, else HTTPS) | `build(..., sshPassed)` |
| P9 github remote when chosen | `build(...)` |
| P9 no other remote (GitHub is reached through the mirror) | `build(...)` adds `origin` only |
| P10 framework Submodule | `install(localProject, ...)` |
| P11 HookSetup, plan gate if chosen | `install(localProject, enablePlanGate)` |
| P12 AGENTS.md and registry copied or kept | `install(...)` returning `templates` |
@@ -218,7 +218,6 @@ destroy SR
[OC-001]: ./oc.md
[DCD-001]: ./dcd.md
[1cd27f7]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/1cd27f77ed844773a969210a11de0d8bb98ac98f
[SD-002]: ../uc-002/sd.md
[DCD-002]: ../dcd.md
[UC-002]: ../uc-002/uc.md
+5 -6
View File
@@ -9,8 +9,8 @@
## Version History
| Date | Status | Author | Reviewer | Change | Commit |
| --- | --- | --- | --- | --- | --- |
| 2026-10-06 | Deprecated | Jens Tirsvad Nielsen | S02 | The license comes from PROJECT_LICENSE (step 6, extension 4c); AGPL-3.0 is only the default when GitHub is chosen | [d773fa9] |
| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S02 | License rule: the AGPL-3.0 default needs GitHub and a public project (step 6, rule 6); step 9 and extension 9e fetch the framework's own submodules | [1cd27f7] |
| 2026-10-08 | Proposed | Jens Tirsvad Nielsen | S02 | Postcondition, step 8 and its rule: origin is the only remote; no github remote (MIL-008) | pending |
---
@@ -33,7 +33,7 @@
- **Postconditions (success guarantee):**
- A repository exists on Gitea under the chosen owner. It is empty, or it holds the license file that applies: the license set in `config.env`, or AGPL-3.0 when the Maintainer chose GitHub, the project is public and no license is set.
- When the Maintainer chose to create a GitHub repository, an empty repository exists on GitHub under the chosen owner, the Gitea repository is a push mirror to it, and the license file, if any, reaches GitHub through the mirror.
- A local project directory exists with credential-free remotes `origin` (Gitea) and, when GitHub was chosen, `github`, the `framework` submodule, installed skills and hooks, and the copied templates.
- A local project directory exists with one credential-free remote, `origin` (Gitea), the `framework` submodule, installed skills and hooks, and the copied templates.
- When the Maintainer agreed, the local project has a `.env` that holds only the credentials the project needs, is readable by its owner only and is ignored by git.
- The Maintainer has a summary of what was created.
@@ -46,7 +46,7 @@
5. Optional: if the Maintainer chose GitHub, the system creates the empty GitHub repository.
6. The system creates the Gitea repository. If a license applies, the repository is created with its license file and so is not empty; otherwise it is empty. The license that applies is the one set in `config.env` (`PROJECT_LICENSE`; `none` means no license); when none is set it is AGPL-3.0 if the Maintainer chose GitHub and the project is public, and none otherwise. The license is never asked.
7. Optional: if GitHub was chosen, the system configures the Gitea repository as a push mirror to GitHub and verifies it. A license file in the Gitea repository is pushed to GitHub by the mirror.
8. The system creates the local project with the `origin` remote and, if GitHub was chosen, the `github` remote.
8. The system creates the local project with the `origin` remote. It adds no `github` remote: a push to `origin` reaches GitHub through the mirror of step 7.
9. The system adds the framework submodule and fetches its own submodules (the `qc` checklists), installs its skills and hooks (and the plan gate if chosen) and copies the templates. If the Maintainer agrees, it also creates the project's own `.env` with the credentials the project needs.
10. The system reports a summary of what was created.
@@ -88,10 +88,10 @@
| 9 | The project's `.env` is the only place a token is written. It is created only after a yes (default no), holds only the keys the project needs (`GITEA_TOKEN`; `GITHUB_PAT` and `GITHUB_USER` when GitHub was chosen), is readable by its owner only, is excluded from git without changing a tracked file, and is never replaced without a yes |
| 3 | The GitHub owner and the Gitea owner are chosen separately; `GITHUB_USER` is only the authenticating account |
| 3 | A project detail set in `config.env` (the key is present, even if empty where an empty value is allowed) is not asked; only the confirmations stay interactive |
| 3, 5, 7 | GitHub is optional; without it no GitHub repository, mirror or `github` remote is created and the GitHub credentials are not required |
| 3, 5, 7 | GitHub is optional; without it no GitHub repository or mirror is created and the GitHub credentials are not required |
| 6 | The license that applies is added to the Gitea repository when it is created, so that repository is not empty: `PROJECT_LICENSE` if set (a Gitea license key such as `MIT`, or `none`), otherwise AGPL-3.0 when GitHub is chosen and the project is public, otherwise none. It is independent of the GitHub choice when set, and it is never asked |
| 7 | The mirror direction is Gitea to GitHub; the GitHub repository stays empty and receives its content from the mirror |
| 8 | `origin` uses HTTPS derived from `GITEA_URL`, or SSH when the SSH test in step 4 passed; when the Gitea repository is not empty (GitHub chosen) the local project is created by fetching it, not by an unrelated `git init` history |
| 8 | `origin` is the only remote, with or without GitHub, and a remote already in the directory, such as a `github` remote made by an earlier version, is never removed or replaced. `origin` uses HTTPS derived from `GITEA_URL`, or SSH when the SSH test in step 4 passed; when the Gitea repository is not empty (GitHub chosen) the local project is created by fetching it, not by an unrelated `git init` history |
| 8, 9 | Nothing is overwritten or deleted without consent, and no commit is made |
### Open Issues
@@ -104,5 +104,4 @@
[US-001]: ../user-stories.md
[SA-001]: ../stakeholder-analysis.md
[DM-001]: ./dm.md
[d773fa9]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/d773fa91df5a54090254e12e074880fb6526a9ff
[1cd27f7]: https://git.tirsystem.com/TirSystem-BashScript/repo_foundry/commit/1cd27f77ed844773a969210a11de0d8bb98ac98f