@techierathore/techieflow 1.0.4 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/TechieFlow/agents/flow-master.md +2 -0
- package/.claude/commands/TechieFlow/agents/verifier.md +2 -2
- package/.claude/commands/TechieFlow/tasks/_develop-mode.md +34 -0
- package/.claude/commands/TechieFlow/tasks/_owner-language.md +1 -0
- package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +4 -3
- package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +2 -2
- package/.claude/commands/TechieFlow/tasks/amend-docs.md +2 -2
- package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +3 -3
- package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +5 -5
- package/.claude/commands/TechieFlow/tasks/develop-end-to-end.md +30 -0
- package/.claude/commands/TechieFlow/tasks/fix-issues.md +3 -2
- package/.claude/commands/TechieFlow/tasks/generate-html.md +2 -2
- package/.claude/commands/TechieFlow/tasks/handoff-phase.md +2 -2
- package/.claude/commands/TechieFlow/tasks/mockups.md +2 -2
- package/.claude/commands/TechieFlow/tasks/productguide.md +2 -2
- package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +1 -1
- package/.claude/commands/TechieFlow/tasks/triage-and-fix.md +2 -2
- package/.claude/commands/TechieFlow/tasks/triage-issues.md +2 -2
- package/.claude/commands/TechieFlow/tasks/verify-phase.md +12 -11
- package/.opencode/plugin/techieflow.js +194 -14
- package/.tfcore/agents/flow-master.md +2 -0
- package/.tfcore/agents/verifier.md +2 -2
- package/.tfcore/core-config.yaml +2 -1
- package/.tfcore/hooks/block-git.sh +4 -2
- package/.tfcore/hooks/guard-build.sh +5 -1
- package/.tfcore/hooks/guard-db.sh +112 -13
- package/.tfcore/hooks/guard-status-html.sh +86 -2
- package/.tfcore/hooks/guard-verify-deps.sh +16 -1
- package/.tfcore/hooks/guard-verify.sh +8 -3
- package/.tfcore/hooks/sweep-artifacts.sh +46 -0
- package/.tfcore/hooks/yolo-allow.sh +27 -0
- package/.tfcore/standards/blazor-zoom.cs.txt +191 -0
- package/.tfcore/standards/coding-standards-dotnet.md +31 -3
- package/.tfcore/standards/owner-words.txt +23 -0
- package/.tfcore/tasks/_develop-mode.md +34 -0
- package/.tfcore/tasks/_owner-language.md +1 -0
- package/.tfcore/tasks/_status-update-gate.md +4 -3
- package/.tfcore/tasks/_yolo-mode.md +2 -2
- package/.tfcore/tasks/amend-docs.md +2 -2
- package/.tfcore/tasks/day1-brownfield.md +3 -3
- package/.tfcore/tasks/day1-greenfield.md +5 -5
- package/.tfcore/tasks/develop-end-to-end.md +30 -0
- package/.tfcore/tasks/fix-issues.md +3 -2
- package/.tfcore/tasks/generate-html.md +2 -2
- package/.tfcore/tasks/handoff-phase.md +2 -2
- package/.tfcore/tasks/mockups.md +2 -2
- package/.tfcore/tasks/productguide.md +2 -2
- package/.tfcore/tasks/render-workflow-docs.md +1 -1
- package/.tfcore/tasks/triage-and-fix.md +2 -2
- package/.tfcore/tasks/triage-issues.md +2 -2
- package/.tfcore/tasks/verify-phase.md +12 -11
- package/.tfcore/telemetry/SCHEMA.md +10 -2
- package/.tfcore/telemetry/install-metrics.sh +3 -2
- package/.tfcore/telemetry/tf-metrics.sh +38 -2
- package/.tfcore/templates/stack-defaults/dotnet.md +3 -1
- package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +6 -0
- package/.tfcore/templates/v4custom/app-architecture-tmpl.md +5 -0
- package/.tfcore/templates/v4custom/app-brd-tmpl.md +7 -4
- package/.tfcore/templates/v4custom/app-checklist-tmpl.md +11 -0
- package/.tfcore/templates/v4custom/app-phase-brd-tmpl.md +94 -0
- package/.tfcore/templates/v4custom/app-phase-uidesign-tmpl.md +60 -0
- package/.tfcore/templates/v4custom/app-phases-tmpl.md +2 -1
- package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +4 -2
- package/.tfcore/templates/v4custom/build-subagent-prompt.md +2 -2
- package/.tfcore/templates/v4custom/html-render-shell.md +6 -2
- package/.tfcore/utils/__pycache__/tf-devguide-list.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-doc-check.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-split-brd.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-status-facts.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-verify-list.cpython-312.pyc +0 -0
- package/.tfcore/utils/tf-appium.mjs +179 -0
- package/.tfcore/utils/tf-assets-browser.mjs +96 -0
- package/.tfcore/utils/tf-assets.sh +97 -12
- package/.tfcore/utils/tf-brd-status.py +14 -5
- package/.tfcore/utils/tf-build-list.py +95 -12
- package/.tfcore/utils/tf-build-list.sh +2 -1
- package/.tfcore/utils/tf-build.sh +163 -15
- package/.tfcore/utils/tf-checklist-edit.py +21 -3
- package/.tfcore/utils/tf-ci-repro.py +685 -0
- package/.tfcore/utils/tf-ci-repro.sh +24 -0
- package/.tfcore/utils/tf-day1-files.py +55 -28
- package/.tfcore/utils/tf-develop.sh +264 -0
- package/.tfcore/utils/tf-devguide-list.py +53 -24
- package/.tfcore/utils/tf-doc-check.py +218 -26
- package/.tfcore/utils/tf-doc-tests.sh +116 -0
- package/.tfcore/utils/tf-emit.sh +132 -45
- package/.tfcore/utils/tf-feedback.sh +13 -0
- package/.tfcore/utils/tf-fix-close.sh +87 -31
- package/.tfcore/utils/tf-goal.sh +12 -12
- package/.tfcore/utils/tf-harness.sh +9 -4
- package/.tfcore/utils/tf-lock.sh +29 -0
- package/.tfcore/utils/tf-log-miss.py +34 -8
- package/.tfcore/utils/tf-login.mjs +167 -0
- package/.tfcore/utils/tf-maccatalyst-check.sh +92 -0
- package/.tfcore/utils/tf-menus.mjs +401 -0
- package/.tfcore/utils/tf-misses-md.py +10 -4
- package/.tfcore/utils/tf-mockup-parity.mjs +763 -71
- package/.tfcore/utils/tf-mockup-parity.sh +25 -2
- package/.tfcore/utils/tf-owner-text.py +233 -0
- package/.tfcore/utils/tf-owner-text.sh +14 -0
- package/.tfcore/utils/tf-phase.sh +38 -4
- package/.tfcore/utils/tf-portable.sh +230 -0
- package/.tfcore/utils/tf-render-html.py +79 -5
- package/.tfcore/utils/tf-req-ids.py +36 -0
- package/.tfcore/utils/tf-selfcheck.sh +39 -6
- package/.tfcore/utils/tf-split-brd.py +11 -1
- package/.tfcore/utils/tf-stack-check.sh +3 -0
- package/.tfcore/utils/tf-status-evidence.sh +11 -9
- package/.tfcore/utils/tf-status-facts.py +160 -45
- package/.tfcore/utils/tf-theme.mjs +189 -0
- package/.tfcore/utils/tf-triage.py +74 -17
- package/.tfcore/utils/tf-triage.sh +2 -0
- package/.tfcore/utils/tf-verify-boot.sh +529 -54
- package/.tfcore/utils/tf-verify-emit.sh +57 -17
- package/.tfcore/utils/tf-verify-env.sh +33 -4
- package/.tfcore/utils/tf-verify-list.py +290 -24
- package/.tfcore/utils/tf-verify-list.sh +3 -1
- package/.tfcore/utils/tf-verify-native.mjs +307 -0
- package/.tfcore/utils/tf-verify-screens.mjs +341 -44
- package/.tfcore/utils/tf-verify-screens.sh +23 -5
- package/.tfcore/utils/tf-verify-tests.sh +310 -19
- package/.tfcore/utils/tf-verify-verdict.py +163 -21
- package/.tfcore/utils/tf-verify-zoom.mjs +193 -0
- package/.tfcore/utils/tf-verify-zoom.sh +29 -0
- package/.tfcore/utils/tf-yolo-alias.sh +84 -0
- package/.tfcore/utils/tf-yolo-perms.py +135 -0
- package/.tfcore/utils/tf-yolo-start.sh +44 -0
- package/.tfcore/utils/tf-yolo.sh +31 -3
- package/.tfcore/utils/tf_defect.py +27 -0
- package/.tfcore/utils/tf_feedback.py +272 -0
- package/.tfcore/utils/tf_roadmap.py +35 -0
- package/.tfcore/utils/tf_stack_check.py +93 -0
- package/README.md +6 -2
- package/docs/TechieFlow-Installation.md +5 -3
- package/opencode.jsonc +6 -2
- package/package.json +1 -1
- package/scripts/install.mjs +13 -2
- package/.tfcore/utils/__pycache__/tf-brd-status.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-codex-bind.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-codex-telemetry.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-day1-files.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-log-miss.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-misses-md.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-mockups-locate.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-opencode-audit.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-render-html.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-triage.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-verify-verdict.cpython-312.pyc +0 -0
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
bash .tfcore/utils/tf-triage.sh <App> note <REQ> "<could not reproduce: what was tried>"
|
|
9
9
|
bash .tfcore/utils/tf-triage.sh <App> close [--started <ISO>] [--verify-ran] [--cmd triage-issues|fix-issues]
|
|
10
10
|
|
|
11
|
+
demote, new and note take --phase N for another phase's checklist; without it demote and note find the
|
|
12
|
+
row in whichever docs/<App>-Checklist.md or docs/<App>-P<N>-Checklist.md holds it.
|
|
13
|
+
|
|
11
14
|
demote the row goes to Needs re-verify (% capped at 75) with a dated Remark holding the symptom in the
|
|
12
15
|
reporter's words, the evidence path and the kind.
|
|
13
16
|
new a defect no row covers: the next free id in the prefix, a Not Started row, a detail entry with the
|
|
@@ -20,7 +23,8 @@ close what triage owes the telemetry, from the actions above (tests/.artifacts
|
|
|
20
23
|
spec for a new row, which the spec never had) (duplicates collapsed through
|
|
21
24
|
tf-emit.sh --open-miss; the origin run looked up with --origin-of), then the run record. It also
|
|
22
25
|
lists every file under src/, source/ or tests/ changed since the start: a triage that edited code
|
|
23
|
-
is reported and logged as an instruction-ignored miss (FR-28).
|
|
26
|
+
is reported and logged as an instruction-ignored miss (FR-28). Only actions logged since the start
|
|
27
|
+
count, and a close empties the list (TrBlazeUI TF-001).
|
|
24
28
|
Exit 0 · 2 could not run.
|
|
25
29
|
"""
|
|
26
30
|
import datetime
|
|
@@ -58,12 +62,47 @@ def cfg_phase():
|
|
|
58
62
|
return 1
|
|
59
63
|
|
|
60
64
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
p = os.path.join("
|
|
64
|
-
if
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
def cfg_project_type():
|
|
66
|
+
"""metrics.project_type from core-config.yaml: a library or docs project has no mockups."""
|
|
67
|
+
p = os.path.join(".tfcore", "core-config.yaml")
|
|
68
|
+
if os.path.isfile(p):
|
|
69
|
+
import re
|
|
70
|
+
m = re.search(r"(?m)^\s+project_type:\s*(\S+)", open(p, encoding="utf-8").read())
|
|
71
|
+
if m:
|
|
72
|
+
return m.group(1).strip("'\"").lower()
|
|
73
|
+
return "app"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def phase_checklist(app, ph):
|
|
77
|
+
return os.path.join("docs", f"{app}-Checklist.md" if ph <= 1 else f"{app}-P{ph}-Checklist.md")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def checklist(app, argv, ce, rid=None):
|
|
81
|
+
"""--phase N names the checklist, as tf-verify-list.py takes it. Without it: the appPhase
|
|
82
|
+
checklist, or, for a row that is not there, the one earlier-phase checklist that holds it —
|
|
83
|
+
a Phase 3 verify finds Phase 1 rows failing, and demote could not reach them (TF-051)."""
|
|
84
|
+
if "--phase" in argv:
|
|
85
|
+
v = opt(argv, "--phase", "")
|
|
86
|
+
if not v.isdigit():
|
|
87
|
+
die("--phase needs a number")
|
|
88
|
+
p = phase_checklist(app, int(v))
|
|
89
|
+
if not os.path.isfile(p):
|
|
90
|
+
die(f"{p} does not exist")
|
|
91
|
+
return p
|
|
92
|
+
p = phase_checklist(app, cfg_phase())
|
|
93
|
+
if rid is None or (os.path.isfile(p) and rid in ce.rows(ce.read(p))):
|
|
94
|
+
if not os.path.isfile(p):
|
|
95
|
+
die(f"{p} does not exist")
|
|
96
|
+
return p
|
|
97
|
+
import glob
|
|
98
|
+
every = sorted(set(glob.glob(os.path.join("docs", f"{app}-Checklist.md")) + glob.glob(os.path.join("docs", f"{app}-P*-Checklist.md"))))
|
|
99
|
+
hits = [c for c in every if rid in ce.rows(ce.read(c))]
|
|
100
|
+
if len(hits) == 1:
|
|
101
|
+
print(f"note: {rid} is a row of {hits[0]}, not of {p}; written there")
|
|
102
|
+
return hits[0]
|
|
103
|
+
if len(hits) > 1:
|
|
104
|
+
die(f"{rid} is a row of {', '.join(hits)}; name one with --phase N")
|
|
105
|
+
die(f"{rid} is not a row of {', '.join(every) or p}")
|
|
67
106
|
|
|
68
107
|
|
|
69
108
|
def log_load():
|
|
@@ -112,7 +151,6 @@ def main(argv):
|
|
|
112
151
|
return 0 if len(argv) > 1 else 2
|
|
113
152
|
app, verb = argv[1], argv[2]
|
|
114
153
|
ce = mod()
|
|
115
|
-
cl = checklist(app)
|
|
116
154
|
log = log_load()
|
|
117
155
|
log.setdefault("app", app)
|
|
118
156
|
now = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
@@ -121,6 +159,7 @@ def main(argv):
|
|
|
121
159
|
if len(argv) < 5:
|
|
122
160
|
die("demote needs <REQ> \"<symptom>\"")
|
|
123
161
|
rid, symptom = argv[3].upper(), argv[4]
|
|
162
|
+
cl = checklist(app, argv, ce, rid)
|
|
124
163
|
kind = opt(argv, "--kind"); ev = opt(argv, "--evidence"); src = opt(argv, "--source", "owner")
|
|
125
164
|
prior = ce.demote(cl, rid, symptom, kind=kind, evidence=ev, source=src, prefix="⚠ prod bug" if src == "production" else "⚠ UAT bug")
|
|
126
165
|
if prior is None:
|
|
@@ -136,9 +175,10 @@ def main(argv):
|
|
|
136
175
|
if len(argv) < 5:
|
|
137
176
|
die("new needs \"<title>\" \"<acceptance>\"")
|
|
138
177
|
title, acc = argv[3], argv[4]
|
|
178
|
+
cl = checklist(app, argv, ce)
|
|
139
179
|
prefix = opt(argv, "--prefix", "FN").upper(); section = opt(argv, "--section"); ev = opt(argv, "--evidence")
|
|
140
180
|
src = opt(argv, "--source", "owner"); mockup = opt(argv, "--mockup")
|
|
141
|
-
if prefix == "UI" and not mockup:
|
|
181
|
+
if prefix == "UI" and not mockup and cfg_project_type() not in ("library", "docs"): # TrBlazeUI TF-003
|
|
142
182
|
print("note: a UI row needs a mockup link; pass --mockup docs/mockups/<screen>.html or the checker will flag it")
|
|
143
183
|
rid = ce.add_row(cl, prefix, title, acc, section=section, mockup=mockup,
|
|
144
184
|
remark=f"logged from {'production' if src == 'production' else 'UAT'} {ce.TODAY}" + (f" (evidence: {ev})" if ev else ""))
|
|
@@ -152,6 +192,7 @@ def main(argv):
|
|
|
152
192
|
if len(argv) < 5:
|
|
153
193
|
die("note needs <REQ> \"<text>\"")
|
|
154
194
|
rid = argv[3].upper()
|
|
195
|
+
cl = checklist(app, argv, ce, rid)
|
|
155
196
|
if ce.note(cl, rid, argv[4]) is None:
|
|
156
197
|
die(f"{rid} is not a row of {cl}")
|
|
157
198
|
log["actions"].append({"verb": "note", "req_id": rid, "symptom": argv[4], "ts": now})
|
|
@@ -162,9 +203,11 @@ def main(argv):
|
|
|
162
203
|
if verb == "close":
|
|
163
204
|
started = opt(argv, "--started") or subprocess.run(["bash", os.path.join(HERE, "tf-phase.sh"), "show"], capture_output=True, text=True).stdout
|
|
164
205
|
if started.startswith("{"):
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
206
|
+
# the marker's own started, never its "outer" block's (TF-052 follow-up)
|
|
207
|
+
try:
|
|
208
|
+
started = (json.loads(started) or {}).get("started") or ""
|
|
209
|
+
except ValueError:
|
|
210
|
+
started = ""
|
|
168
211
|
started = started.strip() if started and not started.startswith("none") else ""
|
|
169
212
|
cmd = opt(argv, "--cmd", "triage-issues")
|
|
170
213
|
# code untouched?
|
|
@@ -173,16 +216,25 @@ def main(argv):
|
|
|
173
216
|
t0 = datetime.datetime.strptime(started, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc).timestamp()
|
|
174
217
|
for top in ("src", "source", "tests"):
|
|
175
218
|
for d, dirs, files in os.walk(top):
|
|
176
|
-
|
|
219
|
+
# a running app's own log files are not code (AppManager TF-026)
|
|
220
|
+
dirs[:] = [x for x in dirs if x not in ("bin", "obj", "node_modules", ".artifacts", "TestResults")
|
|
221
|
+
and x.lower() not in ("logs", "log")]
|
|
177
222
|
for f in files:
|
|
223
|
+
if f.lower().endswith(".log"):
|
|
224
|
+
continue
|
|
178
225
|
p = os.path.join(d, f)
|
|
179
226
|
try:
|
|
180
227
|
if os.path.getmtime(p) > t0:
|
|
181
228
|
changed.append(p.replace("\\", "/"))
|
|
182
229
|
except OSError:
|
|
183
230
|
pass
|
|
184
|
-
|
|
231
|
+
# only this triage's actions: an earlier run's leftovers were logged again under today's run (TrBlazeUI TF-001)
|
|
232
|
+
stale = [a for a in log.get("actions", []) if started and (a.get("ts") or "") < started]
|
|
233
|
+
if stale:
|
|
234
|
+
print(f" skipped {len(stale)} action(s) from before {started} — an earlier triage's, already closed or abandoned")
|
|
235
|
+
acts = [a for a in log.get("actions", []) if a["verb"] in ("demote", "new") and a not in stale]
|
|
185
236
|
gates = misses = 0
|
|
237
|
+
failed = []
|
|
186
238
|
for a in acts:
|
|
187
239
|
rid = a["req_id"]; cls_req = rid.split("-")[1]
|
|
188
240
|
att = q("--next-attempt", rid) or "1"
|
|
@@ -192,7 +244,9 @@ def main(argv):
|
|
|
192
244
|
"gate": "escaped", "gates_run": [], "failure_class": fc, "prior_verdict": a.get("prior")}
|
|
193
245
|
if emit("gates", rec):
|
|
194
246
|
gates += 1
|
|
195
|
-
|
|
247
|
+
else:
|
|
248
|
+
failed.append(a)
|
|
249
|
+
mc =("unspecified-gap" if a["verb"] == "new" else "regression" if (a.get("prior") or "").lower().startswith("verified") else "wrong-behaviour")
|
|
196
250
|
opened = q("--open-miss", rid)
|
|
197
251
|
if opened and opened.split()[-1] == mc:
|
|
198
252
|
print(f" {rid}: already open as {opened.split()[0]} ({mc}); no second miss")
|
|
@@ -210,9 +264,11 @@ def main(argv):
|
|
|
210
264
|
if emit("misses", m):
|
|
211
265
|
misses += 1
|
|
212
266
|
a["miss_id"] = mid
|
|
213
|
-
|
|
267
|
+
elif a not in failed:
|
|
268
|
+
failed.append(a)
|
|
269
|
+
if changed and cmd == "triage-issues" and log.get("code_miss_run") != started:
|
|
214
270
|
mid = q("--next-miss-id")
|
|
215
|
-
log["code_miss_id"] = mid
|
|
271
|
+
log["code_miss_id"] = mid; log["code_miss_run"] = started
|
|
216
272
|
emit("misses", {"kind": "miss", "miss_id": mid, "req_id": None, "req_class": None, "miss_class": "other", "artifact": "src",
|
|
217
273
|
"severity": "major", "why_missed": "instruction-ignored", "origin_phase": "triage-issues", "origin_agent": "flow-master",
|
|
218
274
|
"found_by": "gate", "found_phase": "triage-issues", "found_gate": None, "found_run_id": started, "failure_class": "other",
|
|
@@ -232,6 +288,7 @@ def main(argv):
|
|
|
232
288
|
else:
|
|
233
289
|
ok = None
|
|
234
290
|
log["closed"] = now
|
|
291
|
+
log["actions"] = failed # a closed action is never closed again; one whose record was refused waits for the next close
|
|
235
292
|
log_save(log)
|
|
236
293
|
print(f"triage: {len(acts)} row(s) logged — {gates} gate record(s) (escaped), {misses} miss(es)"
|
|
237
294
|
+ (f", run record {'written' if ok else 'not written'}" if ok is not None else "") + f"; code untouched: {'yes' if not changed else 'NO'}")
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
# bash .tfcore/utils/tf-triage.sh <App> note <REQ> "<could not reproduce: what was tried>"
|
|
7
7
|
# bash .tfcore/utils/tf-triage.sh <App> close [--started <ISO>] [--cmd triage-issues|fix-issues]
|
|
8
8
|
#
|
|
9
|
+
# demote, new and note take --phase N; without it a row of an earlier phase's checklist is found (TF-051).
|
|
10
|
+
#
|
|
9
11
|
# demote: Needs re-verify with a dated Remark in the reporter's words. new: a Not Started row with its
|
|
10
12
|
# acceptance line and BRD-pending. note: a remark, no status change. close: the escaped gate records,
|
|
11
13
|
# one miss per row (found by the owner, the symptom as `what`, duplicates collapsed), the run record,
|