Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27005622e4 | ||
|
|
f395d86db5 | ||
|
|
9747384838 |
@@ -94,9 +94,9 @@ Tests must survive harmless changes to constants, defaults, wording, ordering, f
|
||||
|
||||
Issues live in Gitea at git.westgate.pw (`ShadowsOverWestgate/sow-tools`), managed with the `tea` CLI. Issues follow ownership — file work in the repo that owns it, not the one you happen to be standing in. See `docs/agents/issue-tracker.md`.
|
||||
|
||||
### Triage labels
|
||||
### Labels
|
||||
|
||||
Default label vocabulary (`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`). See `docs/agents/triage-labels.md`.
|
||||
Every issue and PR gets exactly one org-wide `Kind/*` label at creation (`Kind/Bug`, `Kind/Feature`, `Kind/Enhancement`, `Kind/Documentation`, `Kind/Testing`, `Kind/Security`); `Priority/*`, `Status/*`, `Reviewed/*` and `Compat/Breaking` are optional. `tea issues create -L "Kind/Bug"`. See `docs/agents/triage-labels.md`.
|
||||
|
||||
### Domain docs
|
||||
|
||||
|
||||
@@ -59,6 +59,26 @@ preference — move it.
|
||||
`tea pr create`.
|
||||
- **Apply / remove labels**: `tea api --method PATCH` on the issue, or
|
||||
`tea api repos/ShadowsOverWestgate/sow-tools/issues/<number>/labels` endpoints.
|
||||
- **Org-level labels (`Kind/*`, `Priority/*`, `Reviewed/*`, `Status/*`)**: `tea
|
||||
issues edit --add-labels` / `--remove-labels` do **not** apply these on tea
|
||||
0.14.0, the version nixpkgs pins. Name resolution searches only this repo's
|
||||
own label set, so an org label matches nothing and the command exits 0,
|
||||
prints the issue, and changes nothing — no error, no warning. Repo-local
|
||||
labels (`wayfinder:*`, `ready-for-agent`) are unaffected. PRs no-op the same
|
||||
way. Upstream fixed it in v0.15 (`modules/task/labels.go` now also queries
|
||||
`ListOrgLabels`), so this expires when tea is bumped; until then apply org
|
||||
labels in the web UI. Note `tea labels` lists repo labels only, so it will
|
||||
not show you the org set either — `tea api orgs/ShadowsOverWestgate/labels`
|
||||
does.
|
||||
- **Verify every label change by re-reading it.** `tea issues ls -o json` has a
|
||||
`labels` field; use it. A label command exiting 0 is not evidence it applied,
|
||||
and assuming otherwise has already cost one investigation several wrong turns.
|
||||
`tea issues edit --add-labels` works too, org-level labels (`Kind/*`,
|
||||
`Priority/*`) included, but a read-back straight afterwards can still show
|
||||
the old set — `tea issues ls` has returned stale labels for several seconds
|
||||
after an edit that succeeded. Never conclude an edit failed from a single
|
||||
immediate list; re-read after a pause, or use the `labels` endpoints above,
|
||||
whose response *is* the resulting label set and needs no second call.
|
||||
- **Close**: `tea issues close <number>`
|
||||
|
||||
`tea` infers the repo from the git remote when run inside the clone.
|
||||
|
||||
@@ -1,15 +1,101 @@
|
||||
# Triage Labels
|
||||
# Issue and PR labels
|
||||
|
||||
The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker (Gitea — see `issue-tracker.md` for how to apply labels with `tea`).
|
||||
Labels are **org-wide**. They are defined once, for the whole
|
||||
`ShadowsOverWestgate` org, at
|
||||
<https://git.westgate.pw/org/ShadowsOverWestgate/settings/labels>, and every
|
||||
repo in the org can use them. Never create a per-repo copy of a label that
|
||||
already exists at org level.
|
||||
|
||||
| Label in mattpocock/skills | Label in our tracker | Meaning |
|
||||
| -------------------------- | -------------------- | ---------------------------------------- |
|
||||
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
|
||||
| `needs-info` | `needs-info` | Waiting on reporter for more information |
|
||||
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
|
||||
| `ready-for-human` | `ready-for-human` | Requires human implementation |
|
||||
| `wontfix` | `wontfix` | Will not be actioned |
|
||||
## The rule
|
||||
|
||||
When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
|
||||
**Every issue and every pull request gets exactly one `Kind/*` label, at the
|
||||
moment it is created.** Not later, not "when someone triages it". If you open
|
||||
it, you label it.
|
||||
|
||||
Edit the right-hand column to match whatever vocabulary you actually use.
|
||||
An issue with no `Kind/*` label is untriaged. That is the only meaning of
|
||||
"untriaged" here — there is no `needs-triage` label.
|
||||
|
||||
The other groups are optional, and each one is *exclusive*: an issue can carry
|
||||
at most one `Priority/*`, one `Status/*`, and one `Reviewed/*`. Gitea enforces
|
||||
this.
|
||||
|
||||
```sh
|
||||
# always from inside the owning repo's clone
|
||||
tea issues create --title "..." --description "..." --labels "Kind/Bug" </dev/null
|
||||
tea pr create --title "..." --description "..." --labels "Kind/Feature" </dev/null
|
||||
|
||||
# add a label to something that already exists
|
||||
tea api --method POST "repos/ShadowsOverWestgate/<repo>/issues/<n>/labels" \
|
||||
--data '{"labels":["Kind/Bug","Priority/High"]}'
|
||||
```
|
||||
|
||||
## Kind — what this is (pick exactly one)
|
||||
|
||||
| Label | Use it when |
|
||||
| -------------------- | --------------------------------------------------------------- |
|
||||
| `Kind/Bug` | Something that used to work, or is documented to work, does not |
|
||||
| `Kind/Feature` | New functionality that does not exist yet |
|
||||
| `Kind/Enhancement` | Existing functionality gets better, faster, or nicer |
|
||||
| `Kind/Documentation` | Docs, ADRs, runbooks, agent guides |
|
||||
| `Kind/Testing` | Tests, CI checks, contract scripts |
|
||||
| `Kind/Security` | Secrets, auth, permissions, hardening, a vulnerability |
|
||||
|
||||
Bug vs Enhancement, when it is unclear: if the current behaviour is wrong, it
|
||||
is a bug. If the current behaviour is right but weak, it is an enhancement.
|
||||
|
||||
## Priority — how urgent (optional, at most one)
|
||||
|
||||
`Priority/Critical`, `Priority/High`, `Priority/Medium`, `Priority/Low`.
|
||||
|
||||
Leave it off if you do not know. A wrong priority is worse than none.
|
||||
|
||||
## Status — why it is not moving (optional, at most one)
|
||||
|
||||
| Label | Meaning |
|
||||
| ----------------------- | -------------------------------------------- |
|
||||
| `Status/Blocked` | Waiting on another issue, PR, or decision |
|
||||
| `Status/Need More Info` | Waiting on the reporter or on a human answer |
|
||||
| `Status/Abandoned` | Work started and stopped; nobody is on it |
|
||||
|
||||
## Reviewed — the verdict (optional, at most one)
|
||||
|
||||
`Reviewed/Confirmed`, `Reviewed/Duplicate`, `Reviewed/Invalid`,
|
||||
`Reviewed/Won't Fix`. Apply one of these when closing without a fix, so the
|
||||
reason survives.
|
||||
|
||||
## Compat
|
||||
|
||||
`Compat/Breaking` — add it on top of the `Kind/*` label when the change breaks
|
||||
something that already works for a player, an operator, or another repo.
|
||||
|
||||
## Workflow labels (repo-level, not org-level)
|
||||
|
||||
These live in the repo, not the org, and are orthogonal to the groups above:
|
||||
|
||||
- `ready-for-agent` — the spec is complete; an AFK agent may pick this up.
|
||||
No label means it needs a human.
|
||||
- `wayfinder:map`, `wayfinder:task`, `wayfinder:research`,
|
||||
`wayfinder:prototype`, `wayfinder:grilling` — set by `/wayfinder`. Leave
|
||||
them alone unless you are running a wayfinder operation.
|
||||
- `sow-nodebb` also has `package/*` labels naming the plugin or theme a ticket
|
||||
touches.
|
||||
|
||||
## When a skill names a label we do not have
|
||||
|
||||
Skills written elsewhere (mattpocock/skills and friends) use a different
|
||||
vocabulary. Translate it:
|
||||
|
||||
| Skill says | Do this here |
|
||||
| ----------------- | ------------------------------------------------- |
|
||||
| `needs-triage` | Nothing — no `Kind/*` label already means this |
|
||||
| `needs-info` | `Status/Need More Info` |
|
||||
| `ready-for-agent` | `ready-for-agent` |
|
||||
| `ready-for-human` | Nothing — absence of `ready-for-agent` means this |
|
||||
| `wontfix` | `Reviewed/Won't Fix` |
|
||||
|
||||
## Drift check
|
||||
|
||||
`ops/checks/check-labels.sh` in `sow-platform` runs nightly. It compares the
|
||||
live org labels to `ops/policy/labels.yml` and lists every open issue and PR in
|
||||
the org that does not have exactly one `Kind/*` label. That check is the
|
||||
enforcement; this file is the rule.
|
||||
|
||||
@@ -126,8 +126,14 @@ func extractArchiveResources(p *project.Project, archive erf.Archive, desired ma
|
||||
}
|
||||
// *palcus.itp are Toolset-generated palette projections; the module
|
||||
// build regenerates them from source blueprints, so extraction never
|
||||
// writes them back into source.
|
||||
// writes them back into source. The committed skeleton still has to
|
||||
// survive stale cleanup, so mark its target as desired.
|
||||
if ext == "itp" && isPaletteProjectionResref(resource.Name) {
|
||||
effective := p.EffectiveConfig()
|
||||
target, err := extractionTarget(p, "paths.source", effective.Paths.Source, p.SourceDir(), sourceSubdir(ext), strings.ToLower(resource.Name)+"."+ext+".json")
|
||||
if err == nil {
|
||||
desired[target] = struct{}{}
|
||||
}
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -3312,6 +3312,88 @@ func TestExtractOverwritesAndRemovesStaleFiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractKeepsPaletteSkeletonsThroughStaleCleanup(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
mustMkdir(t, filepath.Join(root, "src", "module"))
|
||||
mustMkdir(t, filepath.Join(root, "src", "palettes"))
|
||||
mustMkdir(t, filepath.Join(root, "assets"))
|
||||
mustMkdir(t, filepath.Join(root, "build"))
|
||||
|
||||
mustWriteFile(t, filepath.Join(root, "nwn-tool.json"), `{
|
||||
"module": {
|
||||
"name": "Test Module",
|
||||
"resref": "testmod"
|
||||
},
|
||||
"paths": {
|
||||
"source": "src",
|
||||
"assets": "assets",
|
||||
"build": "build"
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
mustWriteFile(t, filepath.Join(root, "src", "module", "module.ifo.json"), `{
|
||||
"file_type": "IFO ",
|
||||
"file_version": "V3.2",
|
||||
"root": {
|
||||
"struct_type": 0,
|
||||
"fields": [
|
||||
{
|
||||
"label": "Mod_Name",
|
||||
"type": "CExoString",
|
||||
"value": "Original Module"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
skeletonPath := filepath.Join(root, "src", "palettes", "creaturepalcus.itp.json")
|
||||
mustWriteFile(t, skeletonPath, `{
|
||||
"file_type": "ITP ",
|
||||
"file_version": "V3.2",
|
||||
"root": {
|
||||
"struct_type": 0,
|
||||
"fields": [
|
||||
{
|
||||
"label": "MAIN",
|
||||
"type": "List",
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
p, err := project.Load(root)
|
||||
if err != nil {
|
||||
t.Fatalf("load project: %v", err)
|
||||
}
|
||||
if err := p.ValidateLayout(); err != nil {
|
||||
t.Fatalf("validate layout: %v", err)
|
||||
}
|
||||
if err := p.Scan(); err != nil {
|
||||
t.Fatalf("scan: %v", err)
|
||||
}
|
||||
|
||||
if _, err := BuildModule(p); err != nil {
|
||||
t.Fatalf("build module: %v", err)
|
||||
}
|
||||
if err := p.Scan(); err != nil {
|
||||
t.Fatalf("rescan before extract: %v", err)
|
||||
}
|
||||
|
||||
result, err := Extract(p)
|
||||
if err != nil {
|
||||
t.Fatalf("extract: %v", err)
|
||||
}
|
||||
if result.Removed != 0 {
|
||||
t.Fatalf("expected no removed files, got %d", result.Removed)
|
||||
}
|
||||
if _, err := os.Stat(skeletonPath); err != nil {
|
||||
t.Fatalf("expected palette skeleton to survive extract, stat err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractMergesConfiguredGFFJSONFieldsAndLists(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
mustMkdir(t, filepath.Join(root, "src", "module"))
|
||||
|
||||
Reference in New Issue
Block a user