spillwavesolutions/worklog
WikiTicket SDD (worklog): git-native plans, tickets, roadmaps, and wiki publishing. Multi-host bindings. Knowledge-tree writes live in okf-plugin.
Changelog
0.24.12 — 2026-09-19
-
CI can own ticket sync (#413).
ticketing.sync_owner: cimakesworklog-post-mergethe syncer: it names the adapter (WORKLOG_TICKET_ADAPTER, since a runner cannot discover it), caches.work/sync-state.json, runsworklog sync --push-only --forcewith the bot token before rendering, and stages.work/todo.jsonlwith the docs so the link events ride the derived-docs PR. A manual push sync in a CI-owned repo exits 1 without--force;--report,--explain, and--pull-onlystay open;session-doctornotes the ownership.ticketing.ci_dedupe_check: trueaddsworklog dedupe --dry-run --checkto every PR run (new--check: exit 1 on an agreed duplicate group), skipped when the token is absent. New helpersync_dispatch.ticketing_config(). This repository stayssync_owner: human. -
Bot PRs use a maintainer PAT; the status bridge is gone (ADR-0011).
worklog-compactandworklog-post-mergeopen and merge their PRs with theWORKLOG_BOT_PATsecret (fine-grained, contents + pull-requests + issues read/write, one-year expiry; secret created 2026-09-19 with a one-year expiry, so rotate before 2026-09-19 of next year).pull_requestandpushchecks now run natively on bot commits, soplugin/scripts/associate-pr-checks.sh, theworkflow_dispatchwait,actions: write,statuses: write, and theworkflow_runlistener inworklog-invariantsare deleted. Both bot workflows declarepermissions: contents: readand fail at their first step when the secret is missing. Under the strict up-to-date policy a second open bot PR goes stale the moment the first merges, so each bot job closes every openchore/compact-*andchore/post-merge-*PR before regenerating frommain(supersede, not rebase), and merges with--delete-branch. Post-merge skips its own PRs by branch prefix, which with a real identity is required rather than accidental. Thesync --reportstep is no longer masked bycontinue-on-error; a drift finding reaches the PR comment, and a repo with no adapter gets no comment at all. An eviction-only compaction is titledcompact: evict to archiveinstead of repeating last night's watermark.
This closes the plan docs/plans/2026-09-19-review-v0-24-10-and-open-tickets.md (epic #414): every workstream from the v0.24.10 review and issues #412 and #413 is merged. Live design docs regenerate after the tag through the design-docs skill in release mode; the freshness gate blocks the next release if that PR does not land.
0.24.11 — 2026-09-19
-
Release gate for design-doc freshness.
doc-verify --strict(repo-wide runs only, never the--stagedhook) now reportsSTALEand fails when a live design doc'sgit_hashdoes not descend from the latest tag or when that tag has no freeze record indocs/designs/(either<date>_<tag>-release.mdor the historical dated pair). Seven releases (v0.24.4 to v0.24.10) shipped with the live pair stamped at v0.24.3 because the regeneration step was prose. The release skill now spells out theAgentcall and a completion check, and the live pair plus a freeze note for v0.24.10 land with this change. -
worklog initwritesazure-pipelines.ymlfor an Azure DevOps origin (#413). Forge is detected from the origin remote (dev.azure.com,*.visualstudio.com); every other host keeps the GitHub Actions file. Same hook-only steps, existing file never overwritten,uninstallremoves it. A contract test keeps the two templates' commands identical. The user guide gains a "CI wiring" section with the GitHub Actions to Azure Pipelines mapping table. Adapter and CI host are separate axes; no renderer, no forge override key. -
Merge gate: read-only invariants workflow, no bypass actor, ADR-0011.
worklog-invariantsnow declarespermissions: contents: read; it inherited repo-default write, and a commit status namedinvariantsorcoveragefrom any actor withstatuses: writesatisfies the ruleset (integration_idpinning is refused). The deadUser 41898282bypass actor leavesmerge-when-green-ruleset.jsonand the live ruleset. ADR-0011 supersedes ADR-0010, which still claimed Actions pushes derived files straight tomain: bot PRs will use a maintainer PAT sopull_requestchecks run natively, and the status bridge is deleted in the follow-up PR. -
syncno longer mints a duplicate ticket on a clone with no link memory (#412).observe_remotealready listed every remote ticket; it now keeps the marker-to-key map andremembered_keyconsults it as its third source after the log'sexternal.keyand the per-clonelast_pushed_key, so the push is an update and the relink path records the missing link event with no extra API call. Colliding markers resolve to thededupesurvivor. A probe hit that is closed on the remote closes locally instead of pushing. When the listing fails and the clone has no push memory, creates are skipped for that run and the report says why. A deliberateworklog unlinkis never undone by the probe. New:worklog sync --explain <ULID>prints which source answered and changes nothing; the report countsrelinked, and a run that created tickets prints thededupe --dry-runhint;worklog adapter checksays when the clone has no push memory yet. Residual causes stay documented onremembered_key: a capped or lagging listing, or two syncers that both observe absence. -
Retention no longer ping-pongs archived items. The "already snapshotted" check folded
done.jsonlalone, so every archived item looked changed on any active night, got a fresh snapshot back indone.jsonl, and was re-archived a period later next to its old line (v0.24.10 review P0; first evictions were due 2026-10-17). The check now foldsdone.jsonl + archive.jsonl; the archive is pruned of reopened items, items refreshed intodone.jsonl, and older duplicate snapshots (newestevwins). The FIFO cap counts only items with lines indone.jsonl, an unparseabletstakes no cap slot, a parent is not archived while a child is still indone.jsonlor open, a garbage line inarchive.jsonlis dropped with a warning instead of crashing the nightly job, and ignoredretention:values warn.merge-checkfolds the archive so an archived owner still blocks a duplicate link; an untrackedarchive.jsonlnow counts as dirty. Spec §7 renumbered: evict is step 7, verify steps 8 and 9.
Live design docs for this release regenerate after the tag through the design-docs skill in release mode, and the freshness gate in doc-verify --strict blocks the next release if that PR does not land. The v0.24.10 pair and its freeze note landed in #440 with this release's changes. Bot-PR identity (#437) and CI-owned sync (#438) are complete but wait on the WORKLOG_BOT_PAT secret; they ship in the next release.
0.24.10 — 2026-09-02
-
Bot compact PRs land without a maintainer click. GITHUB_TOKEN
pull_requestruns sitaction_required(#403, #408).workflow_dispatchof worklog-invariants does run and produces check-runs on the SHA, but those check-runs do not appear on the PR (statusCheckRollupempty, BLOCKED on #408). Commit statuses namedinvariantsandcoveragedo satisfy the merge-when-green ruleset (#408 merged that way, MERGE, 2 parents). compact.yml and post-merge.yml now dispatch, wait, then post those statuses viaplugin/scripts/associate-pr-checks.sh.statuses: writeadded. Never squash (ADR-0008). -
Nightly compact survives a missing archive.jsonl.
git add .work/archive.jsonlis fatal when retention has never evicted (runs 33369108436, 33482394234). The add is now guarded; missing archive is the designed default. -
merge-when-greenon an already-merged PR exits 0, not 3. CLOSED still exits 3. -
MIGRATE_MS matches MIGRATE_TS. Was 1752883200000 (2025-07-19) while the timestamp said 2026-07-19. Now 1784419200000. Already-migrated ledger events keep their 2025 ULIDs; migrate is one-shot.
-
Retention. Compaction archives closed items older than epic 730d / story 180d / task 90d (then FIFO cap 1000) into
.work/archive.jsonl. Never deletes. Verify isfold(todo+done+archive).worklog showstill finds archived items; the roadmap does not. Plan:docs/plans/2026-08-30-retention.md. -
post-merge.yml parses again. The python heredoc that wrote the sync comment started at column 0, which YAML forbids inside
run: |. GitHub rejected the file at L57 on 0295c50, so the PR-closed job never ran. The comment is now an indentedecho/catwrite still posted via--body-file. -
Merge pipeline actually lands.
worklog sync --reportis an alias of--dry-run(print drift, change nothing) — post-merge CI, the merge-green skill, and the spec all invoked a flag that did not exist. Compact and post-merge no longergit pushmain: GITHUB_TOKEN cannot bypass the merge-when-green ruleset (User 41898282 does not exempt the Actions installation token; Integration 15368 is 422). Both jobs open a PR and armgh pr merge --auto --merge. post-merge has a concurrency group, verifies aftergit add, and posts the sync comment via--body-file(no literal\\n). -
Positioning. README Why leads with frozen plans and
git_hashprovenance, not the JSONL log or a graph-engineering identity claim. New section compares WikiTicket with beads, spec-kit / OpenSpec, and GitHub Projects.docs/graph-engineering.mdis an essay, not the product thesis. -
Truth hygiene. Spec §5.3/§6 match fold.py and ADR-0007 (
evis a total order after dedupe; compaction watermark is per-itemsnapshot.through).status-reportis shipped (§12, §18 step 10). Adapter exit 3 never auto-clearsexternal(ADR-0004). HOSTS.md lists the live Cursor events; PORTS.md says both hook manifests nest underhooks. A plan is the why of a piece of work; an ADR is the why of a standing decision. New design freezes are a tag+hash+delta note, not a 250KB copy; existing dated copies stay frozen. -
triggers: config block.
worklog triggers <event>is the dispatcher for when generation happens (plan-capture,pr-open,pr-merge,release,status-report). Skills read the command instead of hardcoding.pr-mergeis honored in post-merge CI.release.sync_docs/sync.push_on_capture/status.publishare legacy fallbacks; this repo's config usestriggers:only. -
OKF / second-brain write path evicted.
bin/okf_write.py,plugin/scripts/brain_session.py, theworklog-sessionskill, and/worklog:sessionare gone. Knowledge-tree writes live in okf-plugin and second-brain-core.docs/ONBOARDING.mdis a WikiTicket first-hour guide. ISOLATION / GROK_BOT / CURSOR / Deep Agents docs point there.bin/session.pystays (worklog session registry). -
wiki-plan owns frozen-guard and render-hash skip.
worklog wiki-planreads the ia-render manifest and the folded ledger and prints{publish, skip, frozen_violations}. Exit 1 on frozen source_hash drift — do not publish. A frozen page whose banner moved (new render_hash, matching source_hash) is inpublish. wiki-publish skill runs the command instead of hashing files. -
Native auto-merge when green (ADR-0010). Required checks on
main(invariants,coverage), merge-commit only (ADR-0008),allow_auto_mergeon.worklog-post-mergeregenerates roadmap/index after a green merge and postssync --report. The poll loop is fallback. Release stamp, provenance-backfill, and item-close land as one PR. -
Wiki ledger is JSONL, union-merge.
.work/published.json(a 308KB JSON dict with no merge strategy) is now.work/published.jsonl: append-only events, last-write-wins per key,merge=union.worklog wiki-add/wiki-record/wiki-getown the file; the wiki-publish skill must not hand-edit it. Leftover JSON migrates on first write with deterministic ULIDs (#392). -
Compaction preserves open sync conflicts. Snapshots are built from public fields, which stripped
_conflicts; the nightly compact then verified the stripped form and silently dropped every open conflict. Compact now re-emitsconflictevents above each snapshot and verifies the private map too. -
Write envelope, flock, monotonic ULIDs.
worklogbyte-caps the whole encoded event (PIPE_BUF 4096), checksos.write, and holds.work/.lockacross append so a concurrent compact cannot replace the inode mid-write.ulid.new()increments entropy inside the same millisecond so create-then-update cannot fold out of order. -
Merge bootstrap self-heals. SessionStart doctor writes
merge.ours.driverandcore.hooksPath(absolute in linked worktrees).doctor --fix-wiringdoes the same on demand;init.shis worktree-aware. -
Sync correctness. Pull holds the since-cursor when ingest/conflict writes fail;
--keysis forwarded to the adapter as a point query;WORKLOG_TICKET_PROJECTis exported fromticketing.projectwhen unset. GitHubto_lineemits a readable body (so remote body edits conflict instead of being clobbered) and warns at the 1000-issue listing cap. -
Faster merge.
merge-when-greenarmsgh pr merge --auto --mergeup front and polls at 60s as fallback. Never squash (ADR-0008). -
Cursor port.
cursor-hooks.jsonpaths resolve against the plugin root (./hooks/scripts/...). Host-parity test is a real unittest in CI..grok-plugin/marketplace.jsonlocksteps to 0.24.9. -
Version lockstep 0.24.10. Plugin manifests,
bin/worklog, both skill trees, and the README marker all read 0.24.10.
Released with trace-check --strict gaps on historical work, plus this-wave items that are unplanned (no plan) and local-only (no external ticket). This-wave PR/commit links were recorded before the stamp. Reported and accepted rather than skipped silently. doc-verify --strict findings on frozen documents do not gate (ADR-0009). Live design docs regenerate after the tag.
0.24.9 — 2026-08-27
- Push-only sync absorbs tracker-only tickets and closed-on-remote drift (#385).
worklog sync(including--push-only) lists remote tickets with no worklog marker as a first-class drift class and prints theworklog adopt --system … --key …repair. A linked ticket that is closed remotely while the log item is still open is closed locally (worklog close) instead of pushing the open state back over it.worklog adoptcreates the log item, links it, and stamps the ULID marker so the next push updates. Docs: nevergh issue create/gh issue editon a worklog-managed tracker — child worktrees add viaworklogor they do not file tracker issues. - Version lockstep 0.24.9. Plugin manifests,
bin/worklog, both skill trees, and the README marker all read 0.24.9.
Released with trace-check --strict gaps on historical work (none of it from this wave). Reported and accepted rather than skipped silently. doc-verify --strict findings on frozen documents do not gate (ADR-0009). Live design docs regenerate after the tag.
0.24.8 — 2026-08-26
- Lost-link sync no longer mints a second ticket (#382). Create-vs-update now uses
remembered_key: foldedexternal.keyif present, otherwiselast_pushed_keyin gitignored.work/sync-state.json. A checkout that throws away an uncommittedlinkevent updates the original ticket andrecord_linkrestores the folded pointer.worklog unlinkclearslast_pushed_*so a deliberate unlink still files fresh, including for closed items that must not be re-filed. worklog dedupecollapses the extras #382 already minted (#383). Groups by marker ULID, classifies agreed vs mixed-state conflicts, and with--collapse-agreedcloses extras (pointer in the resolution, never deletes) and re-links the survivor. Default is dry-run. Same-title twins without a shared marker are low-confidence and never auto-collapsed.- Generated files stop conflicting on every concurrent branch (#381).
.gitattributesmarksdocs/roadmap.mdanddocs/.index/**merge=ours(named drivergit config merge.ours.driver true, installed byinit.shand the commit hook).pre-merge-commitregenerates from the union-merged log and stages the result before the freshness gate, so the merge commit names both sides' work. - Version lockstep 0.24.8. Plugin manifests,
bin/worklog, both skill trees, and the README marker all read 0.24.8.
0.24.7 — 2026-08-25
- Prompt companion pins.
design-doc-prompt.md,code-walkthrough-prompt.md, andrequirements-doc-prompt.mdnow name the same versions as the skill table:document-specialistv3.2.2,design-doc-mermaidv1.1.1,plantumlv1.2.2,google-docs-stylev1.1.4. PlantUML is leftover types only. - Design docs under
docs/design/(singular) are classified.ia.pymatched onlydocs/designs/(plural), so consumer repos that follow the singular convention inventorieddesign:0with no warning and never wrote those files to the publish manifest (#377). Both paths now classify asdesign. The sidecar normalizer stampsgit_hashfrom the commit that last touched the file when the artifact did not record one, soia-inventory --checkno longer blocks onmissing git_hashafter the path fix.docs/project_notes/is classified asguideso dated cut notes reach the index instead of vanishing. init.shinstallsdoc_verify.py,provenance.py, andhooks/session-end.sh. All three were present, wired, and dead — the pre-commit citation guard is a file-existence test, so a missing module looked like a pass, and the upgrade notes pointedSessionEndat a path init never created (#344). The plugin manifest (Claude, Codex, Cursor) now wiresSessionEndtoo.session-end.shreads the hook payload from stdin instead of a heredoc, so it actually ends the session.- Bot pushes to main now show up in check history. The compact job already ran the suite before pushing (0.24.3).
worklog-invariantsnow also listens onworkflow_runofworklog-compact, which GitHub does fire forGITHUB_TOKENpushes, so a broken compact commit is a red check on main instead of a silent one (#361). - Version lockstep 0.24.7. Plugin manifests,
bin/worklog, both skill trees, and the README marker all read 0.24.7.
Released with trace-check --strict gaps: 50 historical, plus four from this wave (three unplanned items have no plan link; the classify item does not own #377 because the sidecar-stamp item already does). Reported and accepted rather than skipped silently. doc-verify --strict findings on frozen documents do not gate (ADR-0009). Two live-doc drifts on current_design_doc (ia.py _scalar / is_frozen line numbers from this wave) — the live pair regenerates after the tag.
0.24.6 — 2026-08-24
- Claude Code packaging pins. Companion skills now point at the GitHub releases that actually install:
spillwave-documentation-marketplacev0.2.1 (catalog at.claude-plugin/marketplace.jsonwith GitHub source objects),document-specialistv3.2.2,design-doc-mermaidv1.1.1,plantumlv1.2.2,google-docs-stylev1.1.4 (agents is a file array; hooks auto-discover).ste100stays v0.1.4. Claude Code canplugin marketplace add SpillwaveSolutions/spillwave-documentation-marketplacefrom GitHub without a local clone. - Version lockstep 0.24.6. Plugin manifests,
bin/worklog, both skill trees, and the README marker all read 0.24.6.
Released with trace-check --strict gaps on historical work (none of it from this wave). Reported and accepted rather than skipped silently. doc-verify --strict findings on frozen documents do not gate (ADR-0009); live design docs regenerate after the tag.
0.24.5 — 2026-08-24
- Mermaid-first design docs. Architecture docs, code walkthroughs, and requirements now require the Spillwave documentation suite:
document-specialistv3.2.1 writes the prose (STE100 default; Google style only when named) and owns wireframes;design-doc-mermaidv1.1.0 is the default for flowchart, sequence, class, ER, state, C4, and component views;plantumlv1.2.1 is leftover types only (Salt wireframes, use case, timing, ArchiMate, nwdiag, WBS) and always PNG or SVG. Install fromspillwave-documentation-marketplacev0.2.0. - Wiki vs Confluence diagrams. GitHub wiki keeps fenced mermaid and uploads PlantUML images with the page. Confluence uploads images for both mermaid and PlantUML. A wiki page that points at a missing
docs/diagrams/*.pngis a publish defect. - Requirements prompt.
design-docsnow shipsrequirements-doc-prompt.mdfor SRS and PRD, using the same companion skills as the design doc and walkthrough. - Hard bans in both voice packs. No em dash. Do not start a sentence with So, That, Thus, or Hence.
Released with trace-check --strict gaps on historical work (none of it from this wave). Reported and accepted rather than skipped silently. doc-verify --strict findings on frozen documents do not gate (ADR-0009); live design docs regenerate after the tag.
0.24.4
- Three-host hooks: Codex + Cursor-native when Claude hooks exist.
0.24.3 — 2026-08-18
- The Stop hook can see a log you already committed. Its proof that a session recorded work was an uncommitted change to
.work/todo.jsonl, so the rhythm the policy asks for — record first, then commit — erased the evidence and the session got blocked.SessionStartnow stamps the commit the session began at into the session registry, andStopdiffs the log against that fixed point. The marker never moves on later heartbeats, and a missing or unresolvable marker falls back toHEAD, which is the behavior this hook has always had. Trade-off, taken deliberately: a session that pulls someone else's log changes now also reads as having recorded something — a missed nag, where the old direction refused to let a correct session finish its turn. - The nightly compaction job checks itself before it pushes. A push made with the default
GITHUB_TOKENtriggers no other workflow, soworklog-invariantsnever ran on the commit that job creates.mainsat red for two days that way. The job now runshooks/pre-commit, the merge-integrity check and the full suite first, so a bad compaction never lands. It still does not produce a run inmain's check history — only a credential that is notGITHUB_TOKENcan — and that residual gap stays tracked. --keysis documented as what it is. Sync scope is open ∪ hash-dirty ∪--keys: the flag widens a run and can never narrow one. The help text anddocs/worklog-spec.mdnow say so, including why no narrowing flag exists — a sync that skipped dirty items would leave the tracker further from the log, which is the driftsyncexists to close. No behavior change.- Version lockstep repaired. 0.24.2 bumped two of eight version sources;
plugin/plugin.json, both plugin manifests, all fourteen skill frontmatters,bin/worklogand the README marker were left behind. All eight now agree.
Released with 50 trace-check --strict gaps across 29 items — missing PR, ticket and plan links on historical work, none of it from this wave. Reported and accepted rather than skipped silently.
0.24.2 — 2026-08-17
- Cursor host.
.cursor-plugin/plugin.json(Cursor Plugins) plus.cursor/rules/second-brain.mdc. Docs:docs/CURSOR.md.docs/GROK_BOT.mdnow covers Grok Bot spawning Cursor cloud agents.