chore(specs): add scheduler-sim-eager-reconciliation spec, weekly report, cross-spec sequencing notes
New scheduler-sim-eager-reconciliation requirements spec; weekly_report skill; weekly status report for Aug 16-22. Also records cross-spec dependency notes on scheduler-allocation and scheduler-preemption reflecting how scheduler-dispatch-commit's redefined RUN-state timing affects their designs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
parent
548ad9b2e2
commit
0c736c795b
6 changed files with 504 additions and 2 deletions
322
.claude/skills/weekly_report/SKILL.md
Normal file
322
.claude/skills/weekly_report/SKILL.md
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
---
|
||||||
|
name: weekly_report
|
||||||
|
description: Summarize last week's work status into a dated Markdown report. Use when the user asks for a weekly report, weekly summary, week-in-review, or status writeup for a past week.
|
||||||
|
allowed-tools: Read, Write, Bash, Glob, Grep
|
||||||
|
argument-hint: <output-dir> [--week N] [--days mon-sat|mon-sun] [--author <name|email>]
|
||||||
|
triggers:
|
||||||
|
- /weekly_report
|
||||||
|
- weekly report
|
||||||
|
- weekly summary
|
||||||
|
- week in review
|
||||||
|
---
|
||||||
|
|
||||||
|
# weekly_report Skill
|
||||||
|
|
||||||
|
Generate a work-status report for a completed week from repository evidence
|
||||||
|
(git history, spec progress, bug log, session notes) and save it as
|
||||||
|
`<output-dir>/<mmmDD>-<mmmDD>-<YYYY>.md` — e.g. `jun29-jul04-2026.md`.
|
||||||
|
|
||||||
|
## Invocation
|
||||||
|
|
||||||
|
```
|
||||||
|
/weekly_report docs/reports # last complete week -> docs/reports/aug10-aug15-2026.md
|
||||||
|
/weekly_report ~/reports --week 2 # two weeks back
|
||||||
|
/weekly_report docs/reports --days mon-sun
|
||||||
|
/weekly_report docs/reports --author rongsong.shen@gmail.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
| Arg | Default | Meaning |
|
||||||
|
|-----|---------|---------|
|
||||||
|
| `<output-dir>` | `.wolf/reports/` | Directory the report is written to. Created if missing. Announce it when the default is used. |
|
||||||
|
| `--week N` | `1` | How many weeks back. `1` = last complete week, `2` = the one before, `0` = the current (partial) week. |
|
||||||
|
| `--days` | `mon-sat` | Work-week span. `mon-sat` = Mon..Sat (matches the established filename convention), `mon-sun` = Mon..Sun. |
|
||||||
|
| `--author` | *(all)* | Restrict git history to one author. Default includes every author, since agent-assisted commits are attributed to the human owner. |
|
||||||
|
|
||||||
|
## Procedure
|
||||||
|
|
||||||
|
### Step 1 — Resolve the reporting window and filename
|
||||||
|
|
||||||
|
Run this first; everything downstream keys off `$START`, `$END`, and `$SLUG`.
|
||||||
|
|
||||||
|
Use `python3`, **not** `date -d`. The `date` first on PATH in this environment is
|
||||||
|
BusyBox, which silently rejects relative expressions like `-d "-7 days"` and
|
||||||
|
yields empty variables — producing a report over an unbounded window.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
WEEK_OFFSET=1 # from --week: 1 = last complete week, 0 = current
|
||||||
|
SPAN_DAYS=5 # 5 => Mon..Sat (mon-sat), 6 => Mon..Sun (mon-sun)
|
||||||
|
|
||||||
|
eval "$(python3 - "$WEEK_OFFSET" "$SPAN_DAYS" <<'PY'
|
||||||
|
import sys, datetime
|
||||||
|
off, span = int(sys.argv[1]), int(sys.argv[2])
|
||||||
|
t = datetime.date.today()
|
||||||
|
start = t - datetime.timedelta(days=t.weekday()) - datetime.timedelta(weeks=off)
|
||||||
|
end = start + datetime.timedelta(days=span)
|
||||||
|
f = lambda d: d.strftime('%b%d').lower()
|
||||||
|
print(f'START={start}\nEND={end}\nSLUG={f(start)}-{f(end)}-{end.year}')
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
echo "window: $START .. $END -> ${SLUG}.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
Filename rules:
|
||||||
|
- Lowercase 3-letter month + zero-padded day, both endpoints, then the **end date's**
|
||||||
|
year — `jun29-jul04-2026.md`. A window straddling New Year (`dec28`..`jan02`) is
|
||||||
|
therefore `dec28-jan02-2027.md`.
|
||||||
|
- Sanity-check the output before continuing: `$START` must be a Monday and both
|
||||||
|
`$START`/`$END` must be non-empty. Empty values mean the date math failed —
|
||||||
|
stop rather than running git queries with an unbounded `--since`.
|
||||||
|
|
||||||
|
Before writing, check for a collision:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
test -e "$OUT_DIR/$SLUG.md" && echo "EXISTS — do not overwrite without asking"
|
||||||
|
```
|
||||||
|
|
||||||
|
If the file already exists, tell the user and ask whether to overwrite before
|
||||||
|
proceeding. Do not silently replace a prior report.
|
||||||
|
|
||||||
|
### Step 1b — Continuity check: report the GAP, not the calendar default
|
||||||
|
|
||||||
|
**Do this before gathering any evidence.** The naive "last complete ISO week" is
|
||||||
|
frequently the wrong window, because this series is written whenever the user asks,
|
||||||
|
not on a fixed cadence — so the previous report often already covers part or all of it.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -1 "$OUT_DIR"/*.md 2>/dev/null | sort
|
||||||
|
```
|
||||||
|
|
||||||
|
Parse the **end date of the most recent existing report** (from its filename and its
|
||||||
|
`# ... — <range>` heading, which is authoritative when the two disagree). Then:
|
||||||
|
|
||||||
|
- If the last report's end date is **≥ your computed `$END`**, the default window is
|
||||||
|
already covered. Shift the window to `last_end + 1 day` .. the most recent completed
|
||||||
|
day, and rename `$SLUG` to match.
|
||||||
|
- If there is a **gap** between the last report's end and your computed `$START`,
|
||||||
|
the gap is the real reporting window — covering it is the point of the series.
|
||||||
|
- Only fall through to the plain ISO default when no prior report exists.
|
||||||
|
|
||||||
|
Announce the adjustment and why. Real example (2026-08-23): the ISO default resolved
|
||||||
|
to Aug 10–15, but `aug08-aug15-2026.md` already covered it; the genuine gap was
|
||||||
|
**Aug 16–22**, and reporting the default would have produced a duplicate while leaving
|
||||||
|
a week unreported.
|
||||||
|
|
||||||
|
Windows in this series are therefore **not always Mon–Sat** — they are
|
||||||
|
`previous_end + 1` .. `last completed day`. Historical filenames confirm the drift
|
||||||
|
(`jul19-jul26`, `aug08-aug15`). Continuity beats calendar tidiness.
|
||||||
|
|
||||||
|
### Step 2 — Gather git activity
|
||||||
|
|
||||||
|
`--all` walks every local branch, so sibling worktrees of the same repository
|
||||||
|
are covered by one query. Add `--author="$AUTHOR"` to each command when `--author`
|
||||||
|
was passed.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Commit list
|
||||||
|
git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" \
|
||||||
|
--date=format:'%a %m-%d' --pretty=format:'%h%x09%ad%x09%an%x09%s'
|
||||||
|
|
||||||
|
# Volume — headline figure EXCLUDES .wolf/ bookkeeping, which otherwise dominates
|
||||||
|
# (one real week: +288,983 raw vs +28,657 real, from token-ledger.json alone)
|
||||||
|
git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" \
|
||||||
|
--pretty=tformat: --numstat -- . ':(exclude).wolf/*' |
|
||||||
|
awk '{a+=$1; d+=$2; n++} END {printf "%d file-changes, +%d / -%d (non-wolf)\n", n, a, d}'
|
||||||
|
|
||||||
|
# Real vs bookkeeping commit split
|
||||||
|
tot=$(git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" --pretty=format:'%s' | wc -l)
|
||||||
|
real=$(git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" --pretty=format:'%s' \
|
||||||
|
| grep -vc '^chore(wolf)\|^save wolf\|^commit wolf\|^chore: sync harness')
|
||||||
|
echo "$tot commits total, $real real, $((tot-real)) wolf bookkeeping"
|
||||||
|
|
||||||
|
# Where the work landed (component buckets)
|
||||||
|
git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" \
|
||||||
|
--name-only --pretty=format: | grep -v '^$' | sort -u |
|
||||||
|
awk -F/ '{print ($1=="src" ? "src/"$2 : $1)}' | sort | uniq -c | sort -rn
|
||||||
|
|
||||||
|
# Conventional-commit scopes (maps commits to features/specs)
|
||||||
|
git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" \
|
||||||
|
--pretty=format:'%s' | sed -n 's/^[a-z]*(\([^)]*\)).*/\1/p' | sort | uniq -c | sort -rn
|
||||||
|
|
||||||
|
# Branches that received commits in the window
|
||||||
|
git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" \
|
||||||
|
--pretty=format:'%H' | while read -r c; do
|
||||||
|
git branch -a --contains "$c" --format='%(refname:short)'; done | sort -u
|
||||||
|
```
|
||||||
|
|
||||||
|
Read commit bodies (`git show -s --format=%B <sha>`) only for commits whose
|
||||||
|
subject is too terse to classify — do not dump every body into context.
|
||||||
|
|
||||||
|
### Step 3 — Gather spec progress
|
||||||
|
|
||||||
|
Find specs touched during the window, then compute their task completion:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all --no-merges --since="$START 00:00:00" --until="$END 23:59:59" \
|
||||||
|
--name-only --pretty=format: | grep '^\.kiro/specs/' | cut -d/ -f3 | sort -u
|
||||||
|
```
|
||||||
|
|
||||||
|
For each spec name found:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
d=".kiro/specs/$name"
|
||||||
|
jq -r '"phase=\(.phase) ready=\(.ready_for_implementation) blocked=\(.blocked_on // [] | join(","))"' "$d/spec.json"
|
||||||
|
[ -f "$d/tasks.md" ] && printf '%s tasks: %s/%s done\n' "$name" \
|
||||||
|
"$(grep -cE '^\s*- \[x\]' "$d/tasks.md")" "$(grep -cE '^\s*- \[[ x]\]' "$d/tasks.md")"
|
||||||
|
```
|
||||||
|
|
||||||
|
To attribute *which* tasks were completed in the window, diff `tasks.md` across
|
||||||
|
the window boundary rather than reading the current file alone:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git log --all --since="$START 00:00:00" --until="$END 23:59:59" -p \
|
||||||
|
-- ".kiro/specs/$name/tasks.md" | grep -E '^\+\s*- \[x\]'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4 — Gather bug activity
|
||||||
|
|
||||||
|
```bash
|
||||||
|
jq -r --arg s "$START" --arg e "$END" '
|
||||||
|
.bugs[]
|
||||||
|
| select((.timestamp[0:10] >= $s and .timestamp[0:10] <= $e)
|
||||||
|
or ((.last_seen // "")[0:10] >= $s and (.last_seen // "")[0:10] <= $e))
|
||||||
|
| [ .id,
|
||||||
|
.timestamp[0:10],
|
||||||
|
(if (.fix // "") == "" then "OPEN" else "FIXED" end),
|
||||||
|
(.tags // [] | join(",")),
|
||||||
|
(.error_message // "")[0:110]
|
||||||
|
] | @tsv
|
||||||
|
' .wolf/buglog.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Report opened-vs-fixed counts and call out any entry still `OPEN` at window end —
|
||||||
|
those are carry-over risk.
|
||||||
|
|
||||||
|
Two corrections this query needs:
|
||||||
|
|
||||||
|
**Duplicate IDs.** `.wolf/buglog.json` has a history of counter restarts, so an in-window
|
||||||
|
`.timestamp` on a low ID does not mean an old bug was re-touched — it usually means a new
|
||||||
|
entry was appended under an already-used ID. Separate genuinely-new IDs from collisions,
|
||||||
|
and report the collision count as an integrity finding:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# genuinely new (above the prior max) vs collisions
|
||||||
|
jq -r --arg s "$START" --arg e "$END" --argjson floor 1561 '
|
||||||
|
[.bugs[]|select(.timestamp[0:10]>=$s and .timestamp[0:10]<=$e)
|
||||||
|
|.id|capture("^bug-(?<n>[0-9]+)").n|tonumber] | unique
|
||||||
|
| {new: map(select(.>=$floor))|length, collisions: map(select(.<$floor))|length}' .wolf/buglog.json
|
||||||
|
|
||||||
|
# current duplicate-ID census
|
||||||
|
jq -r '[.bugs[].id]|group_by(.)|map(select(length>1))|length' .wolf/buglog.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Set `$floor` to one above the max ID present in the *prior* report's range.
|
||||||
|
|
||||||
|
**Carry-over resolution.** Re-check every bug the previous report listed as open and
|
||||||
|
state its status now — that closing-the-loop line is the series' main continuity value.
|
||||||
|
|
||||||
|
### Step 5 — Gather session notes (optional enrichment)
|
||||||
|
|
||||||
|
`.wolf/memory.md` is large. Extract only session headers inside the window first,
|
||||||
|
and read row detail only where git history is thin on explanation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
awk -v s="$START" -v e="$END" '
|
||||||
|
/^## Session: /{ d=substr($3,1,10); keep = (d>=s && d<=e); if (keep) print; next }
|
||||||
|
keep && /^\| [0-9]/ { c[d]++ }
|
||||||
|
END { for (k in c) printf " %s: %d logged actions\n", k, c[k] }
|
||||||
|
' .wolf/memory.md
|
||||||
|
```
|
||||||
|
|
||||||
|
If the claude-mem MCP tools are available, `timeline` scoped to the window adds
|
||||||
|
narrative context for decisions that never produced a commit. Treat this as
|
||||||
|
optional — never block the report on it.
|
||||||
|
|
||||||
|
### Step 6 — Compose the report
|
||||||
|
|
||||||
|
Write to `$OUT_DIR/$SLUG.md`. **Match the established format of this series** — read the
|
||||||
|
most recent existing report first and mirror its section order. As of Aug 2026 that
|
||||||
|
format is stable across the last three reports:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# XCE Project Status — <Mon DD> – <Mon DD>, <YYYY>
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
<3-5 sentences: the window's theme, what shipped, what regressed. Written so someone
|
||||||
|
who missed the week understands the state without reading further.>
|
||||||
|
|
||||||
|
## Commits by day
|
||||||
|
|
||||||
|
### <Mon DD> (<Day>) — <theme for that day>
|
||||||
|
|
||||||
|
- **`<sha>`** — <what it did and why it matters>
|
||||||
|
|
||||||
|
## Bugs opened/fixed this window
|
||||||
|
|
||||||
|
- **N new bugs** (bug-X – bug-Y), **M fixed**, **K still open**
|
||||||
|
- Carry-over status: which of the *prior report's* open bugs are now closed
|
||||||
|
- Highest-severity fixes, named
|
||||||
|
- ⚠️ Any integrity/regression concern about the bug log itself
|
||||||
|
|
||||||
|
## Spec status changes
|
||||||
|
|
||||||
|
- **<spec>** — <phase transition, task count, and any metadata/reality mismatch>
|
||||||
|
|
||||||
|
## Stats
|
||||||
|
|
||||||
|
- **N commits** — split feature/fix/docs vs `.wolf` bookkeeping
|
||||||
|
- **N files changed**, **+A / −D** — quote the non-`.wolf` figure as the headline
|
||||||
|
- Busiest areas, specs completed, sessions logged
|
||||||
|
|
||||||
|
## Open threads / to-do heading into next session
|
||||||
|
|
||||||
|
1. <numbered, actionable, with enough detail to resume cold>
|
||||||
|
```
|
||||||
|
|
||||||
|
Report-writing rules:
|
||||||
|
- **Evidence-backed only.** Every claim traces to a commit, spec file, or bug entry.
|
||||||
|
Do not infer progress that has no artifact.
|
||||||
|
- **Cite short SHAs inline** so the reader can jump to the diff.
|
||||||
|
- **Day sections get a theme**, not a commit dump — group the day's commits under what
|
||||||
|
the day was actually about ("HA + dispatch firefight", "spec to done in one day").
|
||||||
|
- **Close the loop on the prior report's open threads.** Explicitly state which were
|
||||||
|
resolved and which carried over — that continuity is the series' main value.
|
||||||
|
- **Quote non-`.wolf` line counts as the headline.** `.wolf/token-ledger.json` and
|
||||||
|
`buglog.json` churn dwarfs real code (one week: +288,983 raw vs +28,657 real).
|
||||||
|
Exclude with `-- . ':(exclude).wolf/*'` and mention the raw figure parenthetically.
|
||||||
|
- **Separate bookkeeping commits from real ones** in the count — `chore(wolf)`
|
||||||
|
checkpoints were 89 of 192 commits in one window.
|
||||||
|
- **Language:** English, unless a spec's `spec.json` `language` field says otherwise.
|
||||||
|
- Numbered open threads carry forward; write them so a cold session can act on them.
|
||||||
|
|
||||||
|
### Step 7 — Save and confirm
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p "$OUT_DIR"
|
||||||
|
```
|
||||||
|
|
||||||
|
Write the file with the Write tool, then report back to the user in one or two
|
||||||
|
sentences: the path written, the window covered, and the headline counts
|
||||||
|
(commits / specs advanced / bugs fixed).
|
||||||
|
|
||||||
|
## Safety & Fallback
|
||||||
|
|
||||||
|
**Not a git repository** — report that git evidence is unavailable and build the
|
||||||
|
report from `.wolf/memory.md`, `.wolf/buglog.json`, and `.kiro/specs/` alone.
|
||||||
|
Note the limitation in the report header.
|
||||||
|
|
||||||
|
**Empty window** (no commits, no bug entries, no sessions) — do not fabricate
|
||||||
|
content. Write a short report stating no recorded activity, and ask whether the
|
||||||
|
window was intended (a wrong `--week` offset is the usual cause).
|
||||||
|
|
||||||
|
**Missing `.wolf/` or `.kiro/`** — skip those sections silently; git history alone
|
||||||
|
is a valid basis for the report.
|
||||||
|
|
||||||
|
**Existing report file** — ask before overwriting (see Step 1).
|
||||||
|
|
||||||
|
## After Running
|
||||||
|
|
||||||
|
Per the OpenWolf protocol, append a one-line entry to `.wolf/memory.md` recording
|
||||||
|
the report generation, and add the new report file to `.wolf/anatomy.md`.
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ready_for_implementation": false,
|
"ready_for_implementation": false,
|
||||||
"blocked_on": ["scheduler-core"],
|
"blocked_on": ["scheduler-core", "scheduler-dispatch-commit"],
|
||||||
"sibling_specs": ["scheduler-core", "scheduler-preemption"]
|
"sibling_specs": ["scheduler-core", "scheduler-preemption", "scheduler-dispatch-commit"],
|
||||||
|
"sequencing_note": "Added 2026-08-23 (user directive): blocked on scheduler-dispatch-commit landing first -- this spec's try_alloc_on_host() reads the same resInUse/sharedInUse totals bug-1624 (fixed by scheduler-dispatch-commit) corrupts, and the planned XCE_ALLOC_PREEMPT borrowing mode interacts with what counts as committed/borrowable under that spec's redefined RUN-state timing."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,3 +107,5 @@ J pended → next scheduling round → allocation retries on freed resources
|
||||||
- A job that is not in running state.
|
- A job that is not in running state.
|
||||||
- A job from a queue not listed in the preempting job's `preemptible_queues` list.
|
- A job from a queue not listed in the preempting job's `preemptible_queues` list.
|
||||||
- More victims than necessary to satisfy the preempting job's resource request (minimum sufficient victim set).
|
- More victims than necessary to satisfy the preempting job's resource request (minimum sufficient victim set).
|
||||||
|
|
||||||
|
> **Pending revision (2026-08-23):** the sibling spec `scheduler-dispatch-commit` (not yet designed) redefines "running state" to begin at dispatch-decision-commit time rather than worker-confirmation time — meaning a job could reach RUN with resources committed but no live, signalable process yet. AC6's SIGSTP-to-process-group delivery and AC9's "not in running state" exclusion both assume every RUN job has a live process today; once `scheduler-dispatch-commit` lands, this spec's design phase needs to add a second victim action (cancel an in-flight, unconfirmed dispatch) alongside SIGSTP, and decide whether a dispatched-but-unconfirmed job is eligible as a victim at all. Re-check this note before `scheduler-preemption` proceeds to `/kiro-spec-design`.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Requirements Document
|
||||||
|
|
||||||
|
## Project Description (Input)
|
||||||
|
XCE scheduler operators debugging via simulation-mode replay (`xce_scheduler -i -s <replay>` / batch `--sim`) are the ones affected. Currently, Recorded-Decision Reconciliation (`sim_reconcile_unaccounted_jobs()`, `sim_loop.c`, delivered by the `scheduler-sim-decision-parity` spec, implementation-complete) only succeeds when a job's recorded DISPATCH decision and its `JOB_STATE_CHANGE`-to-RUN confirmation land in the exact same replay round -- it gates on `job->state == RUN` first, then searches that same round's decoded decisions for a match. In any real deployment with genuine dispatch-to-worker-confirmation latency, these two events land in different rounds, so reconciliation never fires for that job -- meaning `scheduler-sim-decision-parity` does not actually fix bug-1611/bug-1613's dominant real-world manifestation (a job dispatched at round N, confirmed running some rounds later, still shows `resInUse=0` / no visible decision when inspected much later in the replay).
|
||||||
|
|
||||||
|
Investigation found the live/normal-mode path already gets this right: `scheduler.c`'s `sched_commit_decision()` sets `job->allocs`/`job->accounts` synchronously at DISPATCH-decision time, completely independent of `job->state` -- and `sched_account_jobs()`'s own charging logic separately gates on `JOB_IS_RUN(job->state)` before checking `job->accounts != NULL`, so a job with accounts already set but still PEND-state is simply not charged yet. This is the correct, already-proven pattern.
|
||||||
|
|
||||||
|
What should change: simulation mode's recorded-decision capture should be decoupled from the RUN-state gate the same way, so it works regardless of how many rounds separate a job's DISPATCH decision from its RUN confirmation. Whenever a round's recorded decision stream contains a DISPATCH decision for a job that does not yet have `job->accounts` set, that decision's allocation data should be captured immediately -- regardless of the job's current state -- rather than waiting for `job->state` to become RUN before searching for a match. `sched_account_jobs()`'s existing RUN-state gate continues to defer actual resource charging until the job's state genuinely transitions to RUN (whenever that recorded event is later replayed), so behavior stays correct even though the underlying allocation data was captured earlier. This must not change `job->state` transition semantics themselves (used elsewhere for job status display, permissions, and preemption logic) -- only how/when the DISPATCH decision's allocation data is captured internally for accounting purposes.
|
||||||
|
|
||||||
|
This is a follow-up to the `scheduler-sim-decision-parity` spec (implementation-complete, all 10 tasks landed and reviewed) -- do not reopen or modify that spec's own requirements/design/tasks. This is its own new spec, building on that feature's existing `sim_reconcile_unaccounted_jobs()` mechanism and round-boundary wiring.
|
||||||
|
|
||||||
|
## Boundary Context
|
||||||
|
- **In scope**: capturing a job's recorded DISPATCH allocation data as soon as simulation-mode replay encounters it in a round's recorded decision stream, regardless of the job's current state at that point; preserving correct, state-gated resource-in-use accounting once capture no longer depends on same-round state coincidence; making the dispatch decision observable at the historically accurate round; preventing double-capture or fabricated data across this wider round span.
|
||||||
|
- **Out of scope**: any change to how or when a job's state itself transitions (PEND/RUN/DONE/etc.) -- state transition timing and triggers are unchanged, only when allocation data is captured for accounting purposes changes; any change to `--sim-verify`'s comparison semantics beyond not producing a new false mismatch as a side effect; any change to simulation mode's live picker (it remains PEND-only for freshly-arriving jobs, unchanged, out of this feature's scope per `scheduler-allocation`); any change to PEND or PREEMPT decision handling; reopening or modifying `scheduler-sim-decision-parity`'s own requirements, design, or tasks; any change to normal-mode (non-simulation) behavior.
|
||||||
|
- **Adjacent expectations**: this feature extends `scheduler-sim-decision-parity`'s existing Recorded-Decision Reconciliation mechanism and round-boundary wiring; it does not replace or duplicate that mechanism. It relies on that feature's decision-reporting channel and resource-accounting service remaining exactly as delivered.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Requirement 1: Cross-round resource-accounting accuracy for dispatched jobs
|
||||||
|
**Objective:** As an operator inspecting simulation-mode resource state, I want a job's resource consumption reflected correctly regardless of how many rounds separate its dispatch from its running confirmation, so that what I inspect during a replay is trustworthy even under realistic dispatch-to-confirmation latency.
|
||||||
|
|
||||||
|
#### Acceptance Criteria
|
||||||
|
1. When simulation-mode replay encounters a round containing a job's originating dispatch decision, the scheduler shall capture that decision's resource-allocation data for the job, regardless of the job's current state at that point.
|
||||||
|
2. While a job's resource-allocation data has been captured but the job has not yet transitioned to a running state, the scheduler shall not include that job's resource consumption in any worker or shared resource-in-use total.
|
||||||
|
3. When a job whose resource-allocation data was already captured subsequently transitions to a running state, the scheduler shall include that job's resource consumption in its worker's and any shared resource's resource-in-use totals from that point forward, regardless of how many rounds elapsed between capture and the transition.
|
||||||
|
4. The scheduler shall report the same resource-in-use totals for a dispatched-then-confirmed-later job as normal-mode execution reported at the equivalent point in the original run, regardless of the round separation between dispatch and confirmation.
|
||||||
|
|
||||||
|
### Requirement 2: Decision visibility at the historically accurate round
|
||||||
|
**Objective:** As an operator watching simulation-mode decision output, I want a job's dispatch decision to become visible when the replay reaches the round it was actually decided in, so I have an accurate picture of when scheduling activity happened, not only that it eventually happened.
|
||||||
|
|
||||||
|
#### Acceptance Criteria
|
||||||
|
1. When simulation-mode replay reaches the round containing a job's originating dispatch decision, the scheduler shall make that decision observable through the existing decision-reporting channel at that round, independent of when the job's state later transitions to running.
|
||||||
|
2. The scheduler shall preserve the original decision's type and resource-allocation detail when reporting it.
|
||||||
|
3. When simulation-mode independently computes a fresh decision for a job in a given round, the scheduler shall report only that one decision for the job, not also a duplicate from the recorded stream.
|
||||||
|
|
||||||
|
### Requirement 3: No fabrication and no double-capture across the wider round span
|
||||||
|
**Objective:** As a maintainer relying on this feature's correctness, I want captured allocation data to never be fabricated or captured more than once, so that widening reconciliation's effective round span does not introduce a new class of correctness risk.
|
||||||
|
|
||||||
|
#### Acceptance Criteria
|
||||||
|
1. The scheduler shall never capture resource-allocation data for a job from anything other than that job's own originating recorded decision.
|
||||||
|
2. Once a job's resource-allocation data has been captured, the scheduler shall not attempt to capture it again from a later round's recorded decisions, regardless of how many further rounds are replayed.
|
||||||
|
3. If a job's resource-allocation data was already captured, and simulation-mode's own live decision-making subsequently produces a fresh decision for that job, the scheduler shall treat the job as already resolved and not overwrite or duplicate its already-captured data.
|
||||||
|
|
||||||
|
### Requirement 4: No regression to existing guarantees
|
||||||
|
**Objective:** As a maintainer relying on `scheduler-sim-decision-parity`'s already-delivered guarantees, I want this feature to preserve them, so existing verification workflows, tests, and behavior continue to hold.
|
||||||
|
|
||||||
|
#### Acceptance Criteria
|
||||||
|
1. The scheduler shall continue to correctly reconcile the same-round dispatch-and-confirmation case that `scheduler-sim-decision-parity` already handles.
|
||||||
|
2. The scheduler shall continue to support decision verification mode (comparing freshly-computed decisions against recorded ones) without reporting a mismatch caused by this feature's own behavior.
|
||||||
|
3. The scheduler shall continue to produce identical decisions between interactive (step-by-step) and batch simulation execution modes.
|
||||||
|
4. While a job has no recorded originating decision available anywhere in the replay's own data (for example, a job already running before the replay's recording window began), the scheduler shall report that job's resource usage as unavailable rather than fabricating a value, and shall continue processing the remainder of the replay without terminating.
|
||||||
|
5. While simulation mode is not enabled, the scheduler shall not change its existing resource-accounting, decision-reporting, or job-state-transition behavior.
|
||||||
22
.kiro/specs/scheduler-sim-eager-reconciliation/spec.json
Normal file
22
.kiro/specs/scheduler-sim-eager-reconciliation/spec.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"feature_name": "scheduler-sim-eager-reconciliation",
|
||||||
|
"created_at": "2026-08-22T14:50:13Z",
|
||||||
|
"updated_at": "2026-08-22T14:58:00Z",
|
||||||
|
"language": "en",
|
||||||
|
"phase": "requirements-generated",
|
||||||
|
"approvals": {
|
||||||
|
"requirements": {
|
||||||
|
"generated": true,
|
||||||
|
"approved": false
|
||||||
|
},
|
||||||
|
"design": {
|
||||||
|
"generated": false,
|
||||||
|
"approved": false
|
||||||
|
},
|
||||||
|
"tasks": {
|
||||||
|
"generated": false,
|
||||||
|
"approved": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ready_for_implementation": false
|
||||||
|
}
|
||||||
103
reports/aug16-aug22-2026.md
Normal file
103
reports/aug16-aug22-2026.md
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
# XCE Project Status — Aug 16 – Aug 22, 2026
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
The week opened by clearing the entire uncommitted backlog the Aug 08–15 report ended on, then ran four specs start-to-finish. **resource-value-verification** (Tue), **build-time-versioning** (Thu), **dirty-content-fingerprint** (Fri), and **scheduler-sim-decision-parity** (Sat) each went spec → implementation → tests inside a single day. Monday was a firefight: seven stacked bugs, one of which (**bug-1569**) was blocking *all* job dispatch. Every one of the prior week's 7 open carry-over bugs is now closed, and 64 new bugs (bug-1561–1624) were opened and fixed within the window. The one thing that got worse: `.wolf/buglog.json` picked up **39 duplicate IDs** from a restarted counter on Aug 15–17.
|
||||||
|
|
||||||
|
## Commits by day
|
||||||
|
|
||||||
|
### Aug 16 (Sun) — clearing the prior week's uncommitted backlog
|
||||||
|
|
||||||
|
- **`d479b707`** — component-failover-adoption Phase 6: closed apiserver's idle-period rejoin gap (bug-1548/bug-1549). This was open thread #1 from last week's report.
|
||||||
|
- **`3afe3d55`** — xceadmin `config dump` command + size-string thresholds (open thread #2).
|
||||||
|
- **`45400c3a`** — controller: closed 6 data-safety races, an apply-pump O(N²) regression, and a boot-time TOCTOU.
|
||||||
|
- **`8a6c339a`** — libxce bug-1425: `jobsubmit` now populates `*jobid` on idempotent-replay success.
|
||||||
|
- **`ce0ee78b`, `5a08dac5`, `570e464d`** — spec metadata reconciliation: promoted 3 new specs, closed 3 stalled specs whose follow-up work had already landed, closed **admin-config-tool** task 6.3 (now 27/27).
|
||||||
|
- **`69f44c2f`** — published the Aug 8–15 weekly report.
|
||||||
|
|
||||||
|
### Aug 17 (Mon) — HA + dispatch firefight (bug-1562 → bug-1569)
|
||||||
|
|
||||||
|
- **`846713ab`** — bug-1562 standby election freeze + bug-1563 flusher retry storm.
|
||||||
|
- **`986a3304`** — bug-1564: `persist_flush` now fires the durable-advance callback.
|
||||||
|
- **`7041d988`** — **bug-1569: three stacked crashes blocking ALL job dispatch.** The week's most severe fix.
|
||||||
|
- **`6e5c3a89`** — bug-1569 companion: worker periodic resval reports were tagged with the wrong host.
|
||||||
|
- **`aabddf60`** — bug-1568: worker resource values always displayed as 0.00.
|
||||||
|
- **`0c8e417b`** — bug-1567: sim-mode picker never learned about the initial snapshot's own jobs/queues.
|
||||||
|
- **`1c943e98`** — bug-1565: `--incremental` flag for `xce-build.sh`.
|
||||||
|
- **`0f1df499`** — bug-1566: standalone xceadmin packaging + deploy-ha usability.
|
||||||
|
- Started **resource-value-verification** (tasks 1.1, 1.2, 2.1).
|
||||||
|
|
||||||
|
### Aug 18 (Tue) — resource-value-verification, spec to done in one day
|
||||||
|
|
||||||
|
- Tasks 2.2 → 8.2 landed: resupdate per-name accept/reject verification, `xce-deploy-ha` apiserver step + `start-all.sh`, scheduler and apiserver resval trace logs, then the four-tier verification chain — worker join/injection (6.1), controller (6.2), scheduler (6.3), apiserver (6.4) — plus verdict aggregation (7.1), live E2E run (8.1), and a verdict-logic selftest (8.2).
|
||||||
|
- **`b406dd76`** — bug-1578 (CRITICAL, reviewer-discovered): `sched_worker_change()` use-after-free on worker disconnect, reproducible controller SIGSEGV.
|
||||||
|
- **`b673b7c9`** — bug-1579 closed for real via `xce_test`'s `!` shell-escape.
|
||||||
|
|
||||||
|
### Aug 19 (Wed) — scheduler-core task 12.5 closeout
|
||||||
|
|
||||||
|
- **`c9acd502`** — clock/resval/jobid-format fixes plus REPL live-operator gaps.
|
||||||
|
- **`a13068dc`** — extended the core-isolation `nm` audit to `core_events.c`/`core_session.c`/`core_clock.c` (Req 5 AC 1/2).
|
||||||
|
- **`b450a680`** — activated virtual-clock logging for sim/REPL sessions (Req 5 AC 3).
|
||||||
|
- **`e52c68f4`** — admission-gated `OPCode_schedAdmin`'s blocking wait (Req 5 AC 10).
|
||||||
|
- **`70fe9e46`** — bug-1589: `dbus_workers_update()` starved workers after the first DONE/EXITED.
|
||||||
|
- **`515f4ca0`** — bug-1588: `job.c` TRACE lines now print human-readable jobids.
|
||||||
|
- **`83e61eec`** — `xce-deploy-ha` gained real `xcecd` worker deployment alongside virtual.
|
||||||
|
|
||||||
|
### Aug 20 (Thu) — build-time-versioning, spec to done in one day (21 tasks)
|
||||||
|
|
||||||
|
- **`1ff9e66c`** spec → **`4b7cc786`** `build_time` meson option → full fan-out across every binary: controller/scheduler `--version` (`88649a04`), worker (`bc5c669b`), apiserver `-version` (`17e837b1`), xcecli via Cobra (`fb09afe6`), xceadmin build-info module + fallback stub (`e1cd9d25`, `7f5c87ce`).
|
||||||
|
- Build plumbing: `xce-build.sh` real commit id/build time (`bca63974`), nix build-phase timestamps (`d08fda76`), `go_build` ldflags injection (`18ae0cc3`, `071f3895`), Makefile ldflags (`45c9b026`).
|
||||||
|
- Three regression scripts: motivating-incident (`0eefc95f`), version/startup-log consistency (`79941a9f`), xceadmin end-to-end build/install/version cycle (`084a5a95`).
|
||||||
|
- Also **`ddee884c`** — bug-1600: `makeGroup()` freed an rtti `makeString()` pointer via raw `free()`, crashing the scheduler during controller failover.
|
||||||
|
- Also **`5147396d`** — controller job `start_time`/`finish_time`/`run_time` were never set by the apply-pump.
|
||||||
|
|
||||||
|
### Aug 21 (Fri) — dirty-content-fingerprint, spec to done in one day (21 tasks)
|
||||||
|
|
||||||
|
- **`d3c583b3`** spec → **`a860141b`** `dirty_fingerprint` meson option + C define → fingerprint surfaced in all six binaries (`fd62e26b`, `d3d9522f`, `a4c1b5ad`, `d65d18ad`, `2bf62a64`, `c79ccf0f`).
|
||||||
|
- Computation paths: nix via `self.narHash` (`fc5cba15`), `xce-build.sh` dev-loop (`c9d40ba1`), Makefile dev-loop (`aa3391a9`), `--version-only` composition (`7ebcba6d`).
|
||||||
|
- Three regression tests: dev-loop distinguishability (`a7d64c82`), startup-log-unchanged consistency (`a4785418`), Nix production-path fingerprint (`f4d2c123`).
|
||||||
|
|
||||||
|
### Aug 22 (Sat) — scheduler-sim-decision-parity, spec to done in one day (13 tasks)
|
||||||
|
|
||||||
|
- **`5f7e1e98`/`25e35bac`** documented the driver-equivalence invariant and scoped the fix; **`0b2c856d`** finalized design + tasks.
|
||||||
|
- Implementation: relocated resource accounting to core level (`3106c82e`), gave sim mode `driver.c`'s round-boundary split (`134380b8`), added reconciliation trigger/lookup (`81358b52`), reconstructed job allocation with safe ownership (`eccba841`), reported reconciled decisions through the existing channel (`0c237f60`), wired reconciliation into the round boundary (`12644094`).
|
||||||
|
- Validation: contention-parity proof (`b3190732`), regression suite for existing guarantees (`88bed529`), live verification against a real 24-round recording (`3c4091d8`), then **`ca01509f`** marked the feature complete.
|
||||||
|
- **`979cd24f`** — scheduler-sim-repl-verbosity spec approved (requirements/design/tasks).
|
||||||
|
- **`1c906e95`** — bug-1588 follow-up: worker job ids print via `fmt_jobid()`.
|
||||||
|
|
||||||
|
## Bugs opened/fixed this window
|
||||||
|
|
||||||
|
- **64 genuinely new bugs** (bug-1561 – bug-1624), **all 64 fixed** — zero left open at window end.
|
||||||
|
- **All 8 carry-over bugs** the prior report listed as open are now FIXED: bug-1508, 1519, 1548, 1549, 1553, 1554, 1557, 1560. That includes bug-1553, which last week's report flagged as "the most concerning open item" (intermittent controller test segfault).
|
||||||
|
- Highest-severity fixes: **bug-1569** (three stacked crashes blocking all job dispatch), **bug-1578** (CRITICAL controller UAF on worker disconnect), **bug-1600** (allocator-mismatch heap corruption during failover), **bug-1572** (scheduler double-free/dangling pointer on resvals delta).
|
||||||
|
- ⚠️ **`.wolf/buglog.json` integrity regressed.** The file grew 917 → 1004 entries, but **39 IDs are now duplicated**: entries appended on Aug 15 (8), Aug 16 (14), and Aug 17 (22) reused the already-taken `bug-875`–`bug-949` range. Example: `bug-908` is both a 2026-06-21 `raft_sim.c` guard-clause bug and a 2026-08-16 `config-upgrade-snapshot/spec.json` refactor note. This is exactly the counter-restart failure the OpenWolf bug-logging rule warns is "unrecoverable without a git-history merge."
|
||||||
|
|
||||||
|
## Spec status changes
|
||||||
|
|
||||||
|
- **resource-value-verification** — created and driven to `implementation-complete` on Aug 17–18. Task checkboxes read 15/23 despite the phase; the trailing 8 are unchecked.
|
||||||
|
- **build-time-versioning** — created and fully implemented Aug 20, **21/21 tasks**, but `spec.json` phase still reads `tasks-generated`. Metadata lag, not work lag.
|
||||||
|
- **dirty-content-fingerprint** — created and fully implemented Aug 21, **21/21 tasks**, same `tasks-generated` phase lag.
|
||||||
|
- **scheduler-sim-decision-parity** — created and completed Aug 22, **13/13 tasks**, phase `implementation-complete`.
|
||||||
|
- **scheduler-sim-repl-verbosity** — spec approved Aug 22, **0/15 tasks**, not started.
|
||||||
|
- **admin-config-tool** — closed Aug 16 at 27/27.
|
||||||
|
- **component-failover-adoption** — Phase 6 fix finally committed Aug 16, closing last week's #1 open thread; checkboxes read 22/27.
|
||||||
|
- Three stalled specs closed Aug 16 as already-superseded by landed work.
|
||||||
|
|
||||||
|
## Stats
|
||||||
|
|
||||||
|
- **192 commits** in the window — **103 feature/fix/docs**, 89 `.wolf` bookkeeping/checkpoint commits.
|
||||||
|
- **218 non-`.wolf` files changed**, **+28,657 / −2,268** lines (excluding `.wolf/`; including it the raw number is +288,983 / −22,630, dominated by `token-ledger.json` and `buglog.json` churn).
|
||||||
|
- Busiest areas: `src/scheduler` (55 files), `.kiro` (54), `src/controller` (25), `src/worker` (13), `src/frontend` (13).
|
||||||
|
- **4 specs implemented end-to-end**, 1 spec closed, 1 spec approved-not-started, 3 stalled specs retired.
|
||||||
|
- **19 sessions** logged in `.wolf/memory.md` across Aug 16–21.
|
||||||
|
- Commits landed on **all 7 days**; peak days Mon and Thu (35 each).
|
||||||
|
|
||||||
|
## Open threads / to-do heading into next session
|
||||||
|
|
||||||
|
1. **Repair the 39 duplicate buglog IDs.** The Aug 15–17 counter restart collided new entries with `bug-875`–`bug-949`. Needs a git-history-informed merge: pull the pre-collision file, identify which of each duplicate pair is the newcomer, and renumber the newcomers above the current max (1624+). The Stop hook validates duplicates, so this will keep flagging until fixed.
|
||||||
|
2. **Sync spec.json phase metadata** for build-time-versioning and dirty-content-fingerprint — both are 21/21 implemented but still read `tasks-generated`.
|
||||||
|
3. **Reconcile resource-value-verification's checkboxes** — phase says `implementation-complete`, tasks say 15/23. Either the last 8 tasks are done-but-unchecked or the phase is premature.
|
||||||
|
4. **scheduler-core is 49/59** and **component-failover-adoption is 22/27** — both sit at `implementation-complete` with unchecked tasks. Same reconcile-or-reopen question.
|
||||||
|
5. **Decide the next spec to start.** scheduler-sim-repl-verbosity is approved at 0/15. A new untracked spec, `scheduler-sim-eager-reconciliation`, appeared in the working tree and is not yet committed.
|
||||||
|
6. **Uncommitted at window end:** `src/scheduler/src/handler.c`, `src/scheduler/testsuite/test_handlers.c`, and untracked generated `src/lib/controller.capnp.{c,h}` — the generated pair should probably be gitignored rather than committed.
|
||||||
|
7. **`.wolf/dashboard-token`** — still untracked, still holding a live-looking token, still not covered by `.gitignore`. Carried over unresolved from last week's item #3.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue