@jenga-ai/agent 1.1.0 → 1.2.0
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/README.md +7 -3
- package/agents/developer.md +82 -2
- package/agents/scrum-master.md +140 -21
- package/agents/tester.md +90 -8
- package/hooks/on_session_end.sh +171 -20
- package/package.json +1 -1
- package/scripts/check-permission-level.sh +107 -0
- package/scripts/check-publicignore-match.sh +122 -0
- package/scripts/check-worktree-liveness.sh +193 -0
- package/scripts/generate-rapport-manifest.sh +43 -0
- package/scripts/idea_manager.sh +47 -0
- package/scripts/install-worktree-commit-guard.sh +134 -0
- package/scripts/jenga-permission-level-switch.sh +109 -0
- package/scripts/smoke-harness.sh +139 -0
- package/scripts/validate-board.sh +62 -0
- package/scripts/with-lock.sh +158 -0
- package/scripts/worktree-remove-guard.sh +204 -0
- package/skills/clearify/SKILL.md +52 -0
- package/skills/commit/SKILL.md +13 -4
- package/skills/distribute/CONFIG_SCHEMA.md +60 -2
- package/skills/do/SKILL.md +48 -11
- package/skills/doc-sync/SKILL.md +16 -0
- package/skills/doc-sync/assets/doc_targets.md +11 -0
- package/skills/idea/SKILL.md +56 -0
- package/skills/idea/assets/idea_handoff_template.md +26 -0
- package/skills/idea/assets/idea_template.md +3 -0
- package/skills/init/SKILL.md +100 -7
- package/skills/init/assets/directory_structure.txt +1 -0
- package/skills/init/assets/workflow_template.json +1 -1
- package/skills/init/scripts/apply-project-visibility.sh +176 -0
- package/skills/init/scripts/detect-existing-codebase.sh +166 -0
- package/skills/init/scripts/init.sh +30 -1
- package/skills/jenga/SKILL.md +160 -17
- package/skills/jenga/scripts/board-scan.sh +238 -0
- package/skills/jenga/scripts/cascade-resolve.sh +297 -0
- package/skills/jenga/scripts/render-confirmation.sh +679 -0
- package/skills/jenga/scripts/render-picker.sh +439 -0
- package/skills/jenga/scripts/resolve-id.sh +367 -0
- package/skills/jenga-permission-level/SKILL.md +81 -0
- package/skills/proceed/SKILL.md +1 -1
- package/skills/publish/SKILL.md +8 -5
- package/skills/publish/assets/ci-contract.md +2 -2
- package/skills/publish/assets/ownership-matrix.md +1 -1
- package/skills/publish/scripts/finalize_changelog.sh +115 -0
- package/skills/publish/scripts/generate_release_notes.sh +475 -28
- package/skills/publish/scripts/npm_ci_pipeline.sh +44 -6
- package/skills/publish/scripts/publish_deploy.sh +38 -8
- package/skills/publish/scripts/run_gates.sh +2 -2
- package/skills/reconcile/SKILL.md +117 -5
- package/skills/reconcile/scripts/detect-unlinked-code.sh +741 -0
- package/skills/skillify/assets/init-new/assets/directory_structure.txt +5 -1
- package/skills/spinoff/SKILL.md +12 -7
- package/skills/todo/SKILL.md +2 -0
- package/skills/uncharted/SKILL.md +711 -0
- package/skills/uncharted/assets/SEGMENT_PROPOSAL_TEMPLATE.md +129 -0
- package/skills/uncharted/assets/UNDERSTANDING_DOC_TEMPLATE.md +160 -0
- package/skills/uncharted/scripts/apply-subsystem-cap.sh +573 -0
- package/skills/uncharted/scripts/detect-dependencies.sh +732 -0
- package/skills/uncharted/scripts/detect-tests.sh +553 -0
- package/skills/uncharted/scripts/discover-subsystems.sh +1029 -0
- package/skills/uncharted/scripts/enumerate-target.sh +470 -0
- package/skills/uncharted/scripts/import-source.sh +517 -0
- package/skills/uncharted/scripts/inspect-provenance.sh +573 -0
- package/skills/uncharted/scripts/resolve-segment-target.sh +640 -0
- package/skills/uncharted/scripts/run-engine.sh +655 -0
- package/skills/uncharted/scripts/validate-proposed-items.sh +125 -0
- package/skills/uncharted/scripts/write-backfilled-epics.sh +498 -0
- package/skills/wtf/SKILL.md +20 -0
- package/templates/CHANGELOG_TEMPLATE.md +13 -0
- package/templates/PROBLEM_RAPPORT_TEMPLATE.md +4 -1
- package/templates/SCRUM_BOARD_SCHEMA.md +157 -10
- package/templates/permission-levels/README.md +73 -0
- package/templates/permission-levels/level-1-locked.json +71 -0
- package/templates/permission-levels/level-2-guarded.json +64 -0
- package/templates/permission-levels/level-3-standard.json +62 -0
- package/templates/permission-levels/level-4-elevated.json +60 -0
- package/templates/permission-levels/level-5-unrestricted.json +58 -0
- package/skills/convert/SKILL.md +0 -124
- package/skills/convert/convert_cli.py +0 -235
- package/skills/convert/tests/sample.csv +0 -4
- package/skills/convert/tests/sample.json +0 -5
- package/skills/convert/tests/sample.jsonl +0 -3
- package/skills/convert/tests/sample.yaml +0 -18
- package/skills/convert/tests/sample_obj.csv +0 -2
- package/skills/convert/tests/sample_obj.json +0 -9
- package/skills/mirror-public/SKILL.md +0 -237
- package/skills/mirror-public/assets/config.json +0 -5
- package/skills/mirror-public/scripts/mirror.sh +0 -374
- package/skills/self-sync/SKILL.md +0 -73
- package/skills/self-sync/scripts/run.js +0 -136
- package/skills/strategy/SKILL.md +0 -312
|
@@ -15,6 +15,7 @@ DROPLET_PIPELINE_SCRIPT="$SCRIPT_DIR/droplet_pipeline.sh"
|
|
|
15
15
|
NPM_CI_PIPELINE_SCRIPT="$SCRIPT_DIR/npm_ci_pipeline.sh"
|
|
16
16
|
RUN_GATES_SCRIPT="$SCRIPT_DIR/run_gates.sh"
|
|
17
17
|
GENERATE_RELEASE_NOTES_SCRIPT="$SCRIPT_DIR/generate_release_notes.sh"
|
|
18
|
+
FINALIZE_CHANGELOG_SCRIPT="$SCRIPT_DIR/finalize_changelog.sh"
|
|
18
19
|
SUGGEST_SEMVER_SCRIPT="$SCRIPT_DIR/suggest_semver_bump.sh"
|
|
19
20
|
WRITE_LEDGER_ENTRY_SCRIPT="$SCRIPT_DIR/write_ledger_entry.sh"
|
|
20
21
|
IOS_PIPELINE_SCRIPT="$SCRIPT_DIR/ios_pipeline.sh"
|
|
@@ -31,6 +32,7 @@ AUTO_YES=0
|
|
|
31
32
|
DRY_RUN=0
|
|
32
33
|
BUMP_OVERRIDE=""
|
|
33
34
|
RELEASE_NOTES_PATH=""
|
|
35
|
+
RELEASE_NOTES_BYPASSED=0
|
|
34
36
|
PROMPT_INPUT_FD=0
|
|
35
37
|
NON_INTERACTIVE=0
|
|
36
38
|
TARGET_TYPE=""
|
|
@@ -41,7 +43,7 @@ SELECTED_VERSION=""
|
|
|
41
43
|
usage() {
|
|
42
44
|
cat <<'USAGE'
|
|
43
45
|
Usage: publish_deploy.sh [--target <name>] [--config <path>] [--yes] [--dry-run]
|
|
44
|
-
[--minor | --major] [--
|
|
46
|
+
[--minor | --major] [--notes-file <path>]
|
|
45
47
|
USAGE
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -290,8 +292,7 @@ generate_release_notes() {
|
|
|
290
292
|
return 0
|
|
291
293
|
fi
|
|
292
294
|
|
|
293
|
-
|
|
294
|
-
local cmd=(bash "$GENERATE_RELEASE_NOTES_SCRIPT" --target "$TARGET_NAME" --output "$RELEASE_NOTES_PATH")
|
|
295
|
+
local cmd=(bash "$GENERATE_RELEASE_NOTES_SCRIPT" --target "$TARGET_NAME")
|
|
295
296
|
if [[ -n "$LAST_TAG" ]]; then
|
|
296
297
|
cmd+=(--from-tag "$LAST_TAG")
|
|
297
298
|
fi
|
|
@@ -299,6 +300,8 @@ generate_release_notes() {
|
|
|
299
300
|
if ! "${cmd[@]}"; then
|
|
300
301
|
fail_with "$EXIT_ADAPTER_FAILURE" "Failed to generate release notes."
|
|
301
302
|
fi
|
|
303
|
+
|
|
304
|
+
RELEASE_NOTES_PATH="$PUBLISH_REPO_ROOT/CHANGELOG.md"
|
|
302
305
|
}
|
|
303
306
|
|
|
304
307
|
review_release_notes() {
|
|
@@ -317,9 +320,18 @@ review_release_notes() {
|
|
|
317
320
|
|
|
318
321
|
resolve_selected_version() {
|
|
319
322
|
local current_version suggested_version
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
+
# For npm/npm-ci targets, package.json is the authoritative version source.
|
|
324
|
+
# The ledger may lag behind if a previous publish didn't bump package.json.
|
|
325
|
+
if [[ "$TARGET_TYPE" == "npm" || "$TARGET_TYPE" == "npm-ci" ]]; then
|
|
326
|
+
local pkg_version
|
|
327
|
+
pkg_version="$(jq -r '.version // empty' "$PUBLISH_REPO_ROOT/package.json" 2>/dev/null || true)"
|
|
328
|
+
current_version="$(publish_normalize_version "$pkg_version" 2>/dev/null)" || current_version=''
|
|
329
|
+
fi
|
|
330
|
+
if [[ -z "$current_version" ]]; then
|
|
331
|
+
current_version="$(publish_latest_ledger_version "$HISTORY_FILE" 2>/dev/null || true)"
|
|
332
|
+
[[ -n "$current_version" ]] || current_version='v0.0.0'
|
|
333
|
+
current_version="$(publish_normalize_version "$current_version")" || current_version='v0.0.0'
|
|
334
|
+
fi
|
|
323
335
|
|
|
324
336
|
suggested_version="$(bash "$SUGGEST_SEMVER_SCRIPT" --yes "$CONFIG_PATH" | tail -n 1 | tr -d '\r')"
|
|
325
337
|
suggested_version="$(publish_normalize_version "$suggested_version")" || fail_with "$EXIT_ADAPTER_FAILURE" "Unable to determine a suggested version."
|
|
@@ -380,7 +392,7 @@ run_adapter_pipeline() {
|
|
|
380
392
|
cmd=(bash "$NPM_PIPELINE_SCRIPT" "$TARGET_NAME" "$CONFIG_PATH")
|
|
381
393
|
;;
|
|
382
394
|
npm-ci)
|
|
383
|
-
cmd=(bash "$NPM_CI_PIPELINE_SCRIPT" --target "$TARGET_NAME" --config "$CONFIG_PATH")
|
|
395
|
+
cmd=(bash "$NPM_CI_PIPELINE_SCRIPT" --target "$TARGET_NAME" --config "$CONFIG_PATH" --version "$SELECTED_VERSION")
|
|
384
396
|
;;
|
|
385
397
|
droplet)
|
|
386
398
|
cmd=(bash "$DROPLET_PIPELINE_SCRIPT" --target "$TARGET_NAME" --config "$CONFIG_PATH")
|
|
@@ -423,6 +435,22 @@ run_post_gates() {
|
|
|
423
435
|
return 1
|
|
424
436
|
}
|
|
425
437
|
|
|
438
|
+
finalize_changelog() {
|
|
439
|
+
# Skipped on a dry run — the real tag and ledger entry are not created
|
|
440
|
+
# either (see write_ledger_entry's own --dry-run handling), and
|
|
441
|
+
# [Unreleased] content from generate_release_notes was still updated
|
|
442
|
+
# earlier in the flow, just left unstamped.
|
|
443
|
+
(( DRY_RUN )) && return 0
|
|
444
|
+
# Skipped when release notes were supplied via the --notes-file bypass
|
|
445
|
+
# flag: RELEASE_NOTES_PATH then points at an arbitrary user-supplied file
|
|
446
|
+
# rather than the standing CHANGELOG.md, so there is no [Unreleased]
|
|
447
|
+
# section of the standing file to finalize.
|
|
448
|
+
(( RELEASE_NOTES_BYPASSED )) && return 0
|
|
449
|
+
|
|
450
|
+
bash "$FINALIZE_CHANGELOG_SCRIPT" "$SELECTED_VERSION" "$RELEASE_NOTES_PATH" \
|
|
451
|
+
|| fail_with "$EXIT_ADAPTER_FAILURE" "Failed to finalize CHANGELOG.md."
|
|
452
|
+
}
|
|
453
|
+
|
|
426
454
|
write_ledger_entry() {
|
|
427
455
|
local platform_state="$1"
|
|
428
456
|
local cmd=(bash "$WRITE_LEDGER_ENTRY_SCRIPT" "$TARGET_NAME" "$TARGET_TYPE" "$platform_state" "$RELEASE_NOTES_PATH" --version "$SELECTED_VERSION" --config "$CONFIG_PATH")
|
|
@@ -483,9 +511,10 @@ parse_args() {
|
|
|
483
511
|
BUMP_OVERRIDE="major"
|
|
484
512
|
shift
|
|
485
513
|
;;
|
|
486
|
-
--
|
|
514
|
+
--notes-file)
|
|
487
515
|
[[ $# -ge 2 ]] || { usage >&2; exit 1; }
|
|
488
516
|
RELEASE_NOTES_PATH="$2"
|
|
517
|
+
RELEASE_NOTES_BYPASSED=1
|
|
489
518
|
shift 2
|
|
490
519
|
;;
|
|
491
520
|
--help|-h)
|
|
@@ -531,6 +560,7 @@ main() {
|
|
|
531
560
|
platform_state="dry-run"
|
|
532
561
|
fi
|
|
533
562
|
|
|
563
|
+
finalize_changelog
|
|
534
564
|
write_ledger_entry "$platform_state"
|
|
535
565
|
print_manual_steps
|
|
536
566
|
}
|
|
@@ -245,7 +245,7 @@ resolve_default_command() {
|
|
|
245
245
|
# fall through to iOS tooling. Missing scripts are announced with a clear
|
|
246
246
|
# informational note (on stderr so it does not pollute the captured
|
|
247
247
|
# command) before the gate is reported as skipped upstream.
|
|
248
|
-
if [[ "$TARGET_TYPE" == "npm" ]]; then
|
|
248
|
+
if [[ "$TARGET_TYPE" == "npm" || "$TARGET_TYPE" == "npm-ci" ]]; then
|
|
249
249
|
case "$gate_name" in
|
|
250
250
|
build|test|lint)
|
|
251
251
|
if find_npm_script_in_root "$gate_name"; then
|
|
@@ -563,7 +563,7 @@ build_gate_list() {
|
|
|
563
563
|
local -a mandatory_pre_gates=()
|
|
564
564
|
|
|
565
565
|
if [[ "$PHASE" == "pre" ]]; then
|
|
566
|
-
if [[ "$TARGET_TYPE" == "npm" ]]; then
|
|
566
|
+
if [[ "$TARGET_TYPE" == "npm" || "$TARGET_TYPE" == "npm-ci" ]]; then
|
|
567
567
|
# npm-specific mandatory gates: test, build, lint (per E26_S06_T03).
|
|
568
568
|
mandatory_pre_gates=(test build lint)
|
|
569
569
|
else
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reconcile
|
|
3
|
-
description: Reconcile the scrum board with actual implementation state. Cross-checks every task's board status against git history and worktrees, merges orphaned worktree branches, demotes unimplemented "Done" items, promotes secretly-implemented items, and cleans stale entries from todo.md. Use when the board feels out of sync, after a big merge session, when tasks were completed outside the normal workflow, or when todo.md has grown stale. Trigger on phrases like "sync the board", "clean up the board", "reconcile", "board is out of date", "todo is stale", or "check what's really done".
|
|
3
|
+
description: Reconcile the scrum board with actual implementation state. Cross-checks every task's board status against git history and worktrees, merges orphaned worktree branches, demotes unimplemented "Done" items, promotes secretly-implemented items, flags code with no board provenance and offers /uncharted segment for it, and cleans stale entries from todo.md. Use when the board feels out of sync, after a big merge session, when tasks were completed outside the normal workflow, or when todo.md has grown stale. Trigger on phrases like "sync the board", "clean up the board", "reconcile", "board is out of date", "todo is stale", or "check what's really done".
|
|
4
4
|
metadata:
|
|
5
5
|
prefered_agent: scrum-master
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Reconcile — Board ↔ Code Synchronisation
|
|
9
9
|
|
|
10
|
-
Walks the full board (epics → stories → tasks), verifies each item's status against what actually exists in git, and fixes any drift. Also cleans `project/todo.md` of entries that are already done.
|
|
10
|
+
Walks the full board (epics → stories → tasks), verifies each item's status against what actually exists in git, and fixes any drift. Also cleans `project/todo.md` of entries that are already done. Then runs the same check in reverse — code that exists with no board item and no EST-tagged commit behind it — and offers `/uncharted segment` for what it finds.
|
|
11
11
|
|
|
12
12
|
## Instructions
|
|
13
13
|
|
|
@@ -80,14 +80,126 @@ At the end of Phase 4, if any DoD gaps were found across any stories, include a
|
|
|
80
80
|
|
|
81
81
|
**Important:** Gap detection is **report-only**. Do not automatically change the status of any story or epic based on unchecked DoD boxes — surface the gaps so a human can review and decide.
|
|
82
82
|
|
|
83
|
-
### 5.
|
|
83
|
+
### 5. Detect unlinked code (no board provenance)
|
|
84
|
+
Phases 2 and 3 ask "does this board item exist in the code?". This phase asks the inverse —
|
|
85
|
+
**"does this code exist on the board?"** — and finds paths with no Jenga provenance at all.
|
|
86
|
+
|
|
87
|
+
Run:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
skills/reconcile/scripts/detect-unlinked-code.sh
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
It emits a single JSON object and exits `0` whether or not it finds anything; read
|
|
94
|
+
`summary.uncharted_paths` rather than branching on the exit status. All the deterministic work —
|
|
95
|
+
exclusions, the board check, the commit check, grouping — is in the script. Everything below is
|
|
96
|
+
judgement and presentation.
|
|
97
|
+
|
|
98
|
+
A path is reported as unlinked only when **both** provenance signals are absent: no board file
|
|
99
|
+
references it, **and** no commit naming a board item added it. Either signal alone is provenance,
|
|
100
|
+
so a file created by a `task(...)` commit is not reported even if no board file names it by path.
|
|
101
|
+
Signal B accepts the current EST tags (`epic(...)`, `story(...)`, `task(E##_S##_T##)`) and the two
|
|
102
|
+
older conventions still present in this repo's history (`E04_S01: ...` and
|
|
103
|
+
`feat(train): implement E01_S05 - ...`).
|
|
104
|
+
|
|
105
|
+
The script reuses the board-linkage check from
|
|
106
|
+
`skills/uncharted/scripts/resolve-segment-target.sh` through its batch interface. Do not
|
|
107
|
+
re-derive linkage yourself, and do not substitute a `grep` over `project/board/` if the script
|
|
108
|
+
fails — a second answer to "is this path on the board" is what that reuse exists to prevent.
|
|
109
|
+
If the script exits non-zero, report the failure in the reconcile report and continue to phase 6.
|
|
110
|
+
|
|
111
|
+
#### Reading the result
|
|
112
|
+
|
|
113
|
+
- **`groups[]`** — the actionable findings, sorted by `unlinked_count` descending. Each entry is
|
|
114
|
+
a directory, not a file, because the useful unit for `/uncharted segment` is a directory or
|
|
115
|
+
feature. Every group directory has itself been checked against the board, so these are
|
|
116
|
+
directories with no provenance of their own either. `fully_unlinked: true` means *every*
|
|
117
|
+
candidate file beneath the directory is unlinked — those are the strongest segment candidates
|
|
118
|
+
and should be offered first. When `false`, the directory holds a mix and only the listed files
|
|
119
|
+
are unlinked.
|
|
120
|
+
- **`covered_groups[]`** — files with no provenance of their own that nonetheless sit under a
|
|
121
|
+
directory the board *does* reference (`directory_linkage.status: "linked"`, with the owning
|
|
122
|
+
board items in `directory_linkage.items` and the spelling that matched in `matched_as`).
|
|
123
|
+
**Do not offer `/uncharted segment` for these** — the board already owns that directory and a
|
|
124
|
+
segment run would duplicate existing items. Mention them in the report as a one-line count so
|
|
125
|
+
the information is not lost, and move on.
|
|
126
|
+
- **`files`** is capped by `--limit` (default 10); `files_truncated` gives the remainder. The
|
|
127
|
+
counts are always true totals, so never re-count `files` to report a number.
|
|
128
|
+
- **`not_checked[]`** — **this is a third state, not a quiet synonym for unlinked.** It means the
|
|
129
|
+
linkage question could not be answered for that path (it is outside the repository, it is the
|
|
130
|
+
repo root, there is no board directory, or it is a stale index entry that no longer exists on
|
|
131
|
+
disk). Report these under their own heading with the `reason` shown, and:
|
|
132
|
+
- **never** describe them as unlinked or add them to the unlinked totals;
|
|
133
|
+
- **never** include them in the `/uncharted segment` offer.
|
|
134
|
+
|
|
135
|
+
A group whose `directory_linkage.status` is `not_checked` is a different case: its *files* were
|
|
136
|
+
checked and are genuinely unlinked, only the directory verdict is missing. Keep offering it, but
|
|
137
|
+
say the directory itself could not be verified.
|
|
138
|
+
|
|
139
|
+
Saying "no board item references this" about a path we never managed to check is a false
|
|
140
|
+
claim of a verified absence. If a `not_checked` entry looks like it matters, the follow-up is
|
|
141
|
+
to investigate that path directly, not to assume the worst about it.
|
|
142
|
+
- **`notices[]`** — surface verbatim in the report if non-empty.
|
|
143
|
+
|
|
144
|
+
#### The `/uncharted segment` offer
|
|
145
|
+
|
|
146
|
+
Drive this off **`summary.uncharted_paths`** and `groups[]`, not `unlinked_paths` —
|
|
147
|
+
`unlinked_paths` includes the covered files, which must never be offered.
|
|
148
|
+
(`unlinked_paths` == `uncharted_paths` + `covered_paths`.)
|
|
149
|
+
|
|
150
|
+
If `summary.uncharted_paths` is `0`, note "no unlinked code found" in the report and continue to
|
|
151
|
+
phase 6. Otherwise present the top groups and offer `/uncharted segment`, using the numbered
|
|
152
|
+
form from `CLAUDE.md`'s Interaction Pattern with the free-text option last:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
Found <N> path(s) with no board provenance, in <M> director(y|ies):
|
|
156
|
+
|
|
157
|
+
1. <directory> — <unlinked_count> file(s)<, entire directory if fully_unlinked>
|
|
158
|
+
2. <directory> — <unlinked_count> file(s)
|
|
159
|
+
...
|
|
160
|
+
|
|
161
|
+
Neither these files nor their directories are referenced by any board item, and no commit
|
|
162
|
+
naming a board item introduced them. How would you like to handle it?
|
|
163
|
+
1. Run `/uncharted segment <directory>` on <top group> now
|
|
164
|
+
2. Choose a different group to run `/uncharted segment` on
|
|
165
|
+
3. Skip for now — carry on with the rest of the reconcile pass
|
|
166
|
+
4. Other (describe below)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
List at most the top 10 groups; if there are more, say how many were not shown.
|
|
170
|
+
|
|
171
|
+
**This offer is non-blocking.** Declining it — option 3, an unrecognised answer, or no answer at
|
|
172
|
+
all — changes nothing about the rest of the reconcile run. Record the finding in the report and
|
|
173
|
+
**continue to phase 6 regardless**. Detection is report-only in the same way DoD gap detection
|
|
174
|
+
is: never change a board status, create a board item, or modify any file on the strength of this
|
|
175
|
+
phase. If the user picks option 1 or 2, finish the reconcile pass first, then hand off to
|
|
176
|
+
`/uncharted segment` at the end so the board is consistent before new items are written.
|
|
177
|
+
|
|
178
|
+
### 6. Clean `project/todo.md`
|
|
84
179
|
Walk the todo entries parsed in phase 1:
|
|
85
180
|
|
|
86
181
|
- **Already-done entries** — if an entry references a task/story/epic whose pre-reconcile status (from the snapshot in phase 1) was already a completed status **and** whose implementation has been confirmed (phase 2), **remove the line entirely** from `project/todo.md`.
|
|
87
182
|
- **Newly-reconciled entries** — entries that were commented out in phase 3 stay as `<!-- RECONCILED: ... -->`.
|
|
88
183
|
- If `project/todo.md` is left with only the header, the format comment, and blank lines, delete the file.
|
|
89
184
|
|
|
90
|
-
###
|
|
91
|
-
Output a reconciliation report using the format in `assets/report_format.md
|
|
185
|
+
### 7. Print a summary
|
|
186
|
+
Output a reconciliation report using the format in `assets/report_format.md`, with one
|
|
187
|
+
additional section from phase 5 placed just before `TODO CLEANUP`:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
🗺️ UNLINKED CODE (no board item for the files or their directory)
|
|
191
|
+
📁 <directory> — <N> file(s) [entire directory]
|
|
192
|
+
📁 <directory> — <N> file(s)
|
|
193
|
+
Offered `/uncharted segment`: <accepted for <directory> | declined>
|
|
194
|
+
Covered: <N> file(s) in <M> director(y|ies) already owned by a board item — not offered
|
|
195
|
+
|
|
196
|
+
❓ NOT CHECKED (board linkage could not be determined — not a finding of unlinked)
|
|
197
|
+
<path> — <reason>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Omit `UNLINKED CODE` when `summary.uncharted_paths` is 0, omit its `Covered:` line when
|
|
201
|
+
`summary.covered_paths` is 0, and omit `NOT CHECKED` when
|
|
202
|
+
`not_checked[]` is empty. Keep the two separate: merging them would report paths as unlinked
|
|
203
|
+
that were never actually checked.
|
|
92
204
|
|
|
93
205
|
If no changes were made, print: `Board and todo.md are in sync — nothing to reconcile. ✅`
|