@zalom/plastic 1.14.1 → 2.0.0-alpha.10
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/PLASTIC.md +101 -294
- package/README.md +5 -6
- package/agents/plastic-advisor.md +18 -17
- package/agents/plastic-enforcer.md +57 -69
- package/agents/plastic-executor.md +34 -20
- package/agents/plastic-faux-advisor.md +18 -18
- package/bin/lib/context_budget.rb +453 -0
- package/bin/plastic-bench +78 -0
- package/config_asks.yml +38 -0
- package/hooks/capture +4 -0
- package/hooks/close +5 -0
- package/hooks/hooks.json +14 -42
- package/hooks/message-display +81 -0
- package/hooks/record +4 -0
- package/hooks/savepoint +5 -5
- package/package.json +3 -2
- package/scripts/agent-report +15 -10
- package/scripts/append-ledger +208 -0
- package/scripts/codex-hook +78 -90
- package/scripts/dashboard.rb +43 -14
- package/scripts/day-summary +53 -0
- package/scripts/doctor.rb +269 -43
- package/scripts/end-intent +170 -76
- package/scripts/exec-worktree +11 -20
- package/scripts/file-session-intent +61 -0
- package/scripts/hook-capture +255 -0
- package/scripts/hook-close +36 -0
- package/scripts/hook-message-display +74 -0
- package/scripts/hook-record +157 -0
- package/scripts/hook-savepoint +45 -0
- package/scripts/hook-session-start +128 -12
- package/scripts/install.rb +8 -6
- package/scripts/intent-screen +77 -0
- package/scripts/lib/agent_models.rb +1 -7
- package/scripts/lib/arm.rb +308 -0
- package/scripts/lib/backfill_intent.rb +316 -0
- package/scripts/lib/bridge.rb +24 -1597
- package/scripts/lib/compact_instructions.rb +56 -0
- package/scripts/lib/day_summary.rb +211 -0
- package/scripts/lib/doctor_core.rb +66 -88
- package/scripts/lib/doctor_session_ledger.rb +158 -0
- package/scripts/lib/exec_worktree.rb +14 -60
- package/scripts/lib/handoff.rb +184 -0
- package/scripts/lib/harness_text.rb +5 -4
- package/scripts/lib/hook_registry.rb +57 -106
- package/scripts/lib/insights.rb +3 -4
- package/scripts/lib/installer_core.rb +136 -41
- package/scripts/lib/intent_screen.rb +309 -0
- package/scripts/lib/intent_screen_ansi.rb +262 -0
- package/scripts/lib/lock.rb +6 -26
- package/scripts/lib/message_display.rb +290 -0
- package/scripts/lib/outcome_guard.rb +7 -5
- package/scripts/lib/project_validator.rb +30 -1
- package/scripts/lib/report_screen.rb +648 -0
- package/scripts/lib/roadmap_queue.rb +3 -3
- package/scripts/lib/roadmap_savepoint.rb +1 -1
- package/scripts/lib/rule_catalog.rb +6 -3
- package/scripts/lib/savepoint.rb +334 -0
- package/scripts/lib/scaffold_intent.rb +13 -179
- package/scripts/lib/screen_paint.rb +276 -0
- package/scripts/lib/session_backfill.rb +184 -0
- package/scripts/lib/session_close.rb +104 -0
- package/scripts/lib/session_git.rb +500 -0
- package/scripts/lib/session_ledger.rb +621 -0
- package/scripts/lib/store_discovery.rb +1 -1
- package/scripts/lib/store_provisioning.rb +1 -1
- package/scripts/maintenance-run +7 -7
- package/scripts/new-intent +63 -4
- package/scripts/plastic-lock +101 -41
- package/scripts/promote-session-item +150 -0
- package/scripts/read-config +3 -0
- package/scripts/rebuild-graph +1 -1
- package/scripts/report-screen +120 -0
- package/scripts/roadmap-next +2 -2
- package/scripts/rollback.rb +48 -3
- package/scripts/savepoint-note +67 -0
- package/scripts/scaffold-intent +37 -63
- package/scripts/session-commit +116 -0
- package/scripts/spawn-preamble +14 -7
- package/scripts/update.rb +7 -3
- package/scripts/write-handoff +60 -0
- package/skills/agent-advisor/SKILL.md +3 -3
- package/skills/agent-advisor/references/advisor-protocol.md +20 -20
- package/skills/auto/SKILL.md +223 -317
- package/skills/auto/evals/evals.json +10 -10
- package/skills/auto/references/agent-architecture.md +102 -90
- package/skills/auto/references/agent-report-contract.md +4 -21
- package/skills/auto/references/end-tail.md +47 -53
- package/skills/auto/references/human-report-contract.md +62 -56
- package/skills/conventions/SKILL.md +1 -3
- package/skills/conventions/references/lifecycle-and-savepoints.md +35 -1
- package/skills/conventions/references/locks-and-worktrees.md +62 -58
- package/skills/conventions/references/maintenance-and-revisions.md +12 -12
- package/skills/dashboard/SKILL.md +1 -1
- package/skills/direct/SKILL.md +66 -0
- package/skills/direct/references/request-signals.md +59 -0
- package/skills/doctor/SKILL.md +58 -11
- package/skills/doctor/report.md +3 -1
- package/skills/install/SKILL.md +11 -9
- package/skills/intent-continuing/SKILL.md +142 -91
- package/skills/intent-continuing/references/boarding-matrix.md +34 -0
- package/skills/intent-continuing/references/context-management.md +3 -3
- package/skills/intent-creating/SKILL.md +2 -2
- package/skills/intent-creating/references/lifecycle.md +1 -1
- package/skills/intent-ending/SKILL.md +34 -37
- package/skills/intent-ending/evals/evals.json +4 -4
- package/skills/intent-executing/SKILL.md +15 -46
- package/skills/intent-executing/plan-reviewer-prompt.md +39 -0
- package/skills/intent-speccing/SKILL.md +108 -51
- package/skills/intent-speccing/evals/evals.json +5 -5
- package/skills/intent-speccing/references/per-section-fill-rules.md +4 -4
- package/skills/intent-speccing/references/self-verify-checklist.md +1 -2
- package/skills/project-creating/SKILL.md +1 -1
- package/skills/releasing/SKILL.md +7 -8
- package/skills/tutorial/SKILL.md +2 -2
- package/skills/tutorial/references/track-1-guided.md +16 -18
- package/skills/tutorial/references/track-2-auto.md +12 -13
- package/skills/tutorial/references/track-3-projects-and-roadmaps.md +2 -2
- package/templates/agents.md +4 -7
- package/templates/config.yml +5 -0
- package/templates/intent-screen.md +17 -0
- package/templates/outcome.md +14 -1
- package/templates/project.yml +7 -0
- package/templates/report-state.md +11 -0
- package/templates/roadmap.md +1 -1
- package/templates/savepoint.md +2 -2
- package/templates/session-intent.md +29 -0
- package/agents/plastic-brainstorming.md +0 -48
- package/agents/plastic-future-intent-researcher.md +0 -35
- package/agents/plastic-intent-curator.md +0 -47
- package/agents/plastic-intent-discovery.md +0 -43
- package/agents/plastic-planner.md +0 -56
- package/agents/plastic-spec-specialist.md +0 -53
- package/hooks/auto-arm +0 -5
- package/hooks/bash-gate +0 -3
- package/hooks/continue +0 -31
- package/hooks/edit-gates +0 -3
- package/hooks/future-intent-check +0 -25
- package/hooks/gate-check +0 -12
- package/hooks/power-tools +0 -8
- package/scripts/hook-auto-arm +0 -51
- package/scripts/hook-bash-gate +0 -78
- package/scripts/hook-code-gate +0 -38
- package/scripts/hook-continue +0 -48
- package/scripts/hook-create-gate +0 -51
- package/scripts/hook-edit-gates +0 -58
- package/scripts/hook-future-intent-check +0 -90
- package/scripts/hook-gate-check +0 -169
- package/scripts/hook-links-gate +0 -54
- package/scripts/hook-lock-gate +0 -47
- package/scripts/hook-power-tools +0 -38
- package/scripts/hook-savepoint-pre +0 -32
- package/scripts/lib/codex_edit_gates.rb +0 -138
- package/scripts/lib/edit_gates.rb +0 -398
- package/scripts/lib/links_gate.rb +0 -140
- package/scripts/lib/qmd_hook.rb +0 -41
- package/scripts/lib/spec_header.rb +0 -83
- package/scripts/lib/start_intent.rb +0 -296
- package/scripts/start-intent +0 -89
- package/skills/_active-intent-gate.md +0 -26
- package/skills/auto/references/tiers.md +0 -100
- package/skills/continuing/SKILL.md +0 -34
- package/skills/continuing/evals/evals.json +0 -91
- package/skills/conventions/references/gates-and-enforcement.md +0 -53
- package/skills/conventions/references/tiers-and-dispatch.md +0 -135
- package/skills/doctor/references/gates-stuck-detection.md +0 -43
- package/skills/intent-brainstorming/SKILL.md +0 -118
- package/skills/intent-brainstorming/evals/evals.json +0 -67
- package/skills/intent-continuing/evals/evals.json +0 -145
- package/skills/intent-discovering/SKILL.md +0 -56
- package/skills/intent-grilling/SKILL.md +0 -108
- package/skills/intent-linking/SKILL.md +0 -128
- package/skills/intent-linking/evals/evals.json +0 -22
- package/skills/intent-linking/references/zettelkasten.md +0 -45
- package/skills/intent-locking/SKILL.md +0 -64
- package/skills/intent-planning/SKILL.md +0 -145
- package/skills/intent-planning/evals/evals.json +0 -81
- package/skills/intent-planning/references/plan-format.md +0 -130
- package/skills/intent-researching/SKILL.md +0 -123
- package/skills/intent-researching/evals/evals.json +0 -22
- package/skills/intent-savepoint/SKILL.md +0 -83
- package/skills/intent-savepoint/references/context-management.md +0 -32
- package/skills/intent-starting/SKILL.md +0 -151
- package/skills/intent-starting/evals/evals.json +0 -117
- package/skills/intent-starting/references/boarding-matrix.md +0 -35
- package/skills/project-continuing/SKILL.md +0 -119
- package/skills/project-continuing/evals/evals.json +0 -100
- package/skills/roadmap-continuing/SKILL.md +0 -89
- package/skills/roadmap-continuing/evals/evals.json +0 -82
- package/skills/skill-creating/SKILL.md +0 -75
- package/skills/skill-creating/evals/evals.json +0 -108
- package/skills/skill-creating/references/agents.md +0 -168
- package/skills/skill-creating/references/defaults-first.md +0 -23
- package/skills/skill-creating/references/evals.md +0 -41
- package/skills/skill-creating/references/hooks.md +0 -251
- package/skills/skill-creating/references/progressive-disclosure.md +0 -176
- package/skills/skill-creating/references/scripts.md +0 -166
- package/skills/skill-creating/references/skills.md +0 -169
- package/skills/skill-creating/scripts/scaffold.rb +0 -313
- package/skills/skill-evaluating/SKILL.md +0 -141
- package/skills/skill-evaluating/assets/eval-template.json +0 -12
- package/skills/skill-evaluating/evals/evals.json +0 -75
- package/skills/skill-evaluating/references/convention-checks.md +0 -76
- package/skills/skill-evaluating/references/eval-methodology.md +0 -154
- package/skills/store-curating/SKILL.md +0 -64
- package/skills/store-curating/evals/evals.json +0 -38
- package/skills/store-indexing/SKILL.md +0 -93
- package/skills/store-indexing/evals/evals.json +0 -22
- package/skills/store-indexing/references/zettelkasten-linking.md +0 -32
- package/skills/store-provisioning/SKILL.md +0 -55
- /package/skills/{project-continuing → intent-continuing}/references/board-fill.md +0 -0
- /package/skills/{roadmap-continuing → intent-continuing}/references/liveness-ranking.md +0 -0
- /package/skills/{intent-brainstorming → intent-speccing}/references/design-principles.md +0 -0
package/scripts/doctor.rb
CHANGED
|
@@ -21,7 +21,7 @@ require_relative "lib/store_discovery"
|
|
|
21
21
|
require_relative "lib/links_projection"
|
|
22
22
|
require_relative "lib/links_section"
|
|
23
23
|
require_relative "lib/lock"
|
|
24
|
-
require_relative "lib/
|
|
24
|
+
require_relative "lib/savepoint"
|
|
25
25
|
require_relative "lib/agent_models"
|
|
26
26
|
require_relative "lib/outcome_guard"
|
|
27
27
|
require_relative "lib/skill_lint"
|
|
@@ -29,6 +29,7 @@ require_relative "lib/config_asks"
|
|
|
29
29
|
require_relative "lib/power_tools"
|
|
30
30
|
require_relative "lib/preflight"
|
|
31
31
|
require_relative "lib/ruby_probe"
|
|
32
|
+
require_relative "lib/doctor_session_ledger"
|
|
32
33
|
|
|
33
34
|
# Diagnostic engine, instantiable with an injected store/agent map so tests can
|
|
34
35
|
# run it hermetically (no eval, no global-constant rewriting).
|
|
@@ -37,6 +38,7 @@ require_relative "lib/ruby_probe"
|
|
|
37
38
|
# store, conventions, intent and CLI halves, so Doctor stays one class with one
|
|
38
39
|
# public surface.
|
|
39
40
|
class Doctor
|
|
41
|
+
include DoctorSessionLedger
|
|
40
42
|
|
|
41
43
|
REQUIRED_INDEX_SECTIONS = ["## Active", "## Future", "## Clusters", "## Abandoned", "## Completed"].freeze
|
|
42
44
|
|
|
@@ -286,6 +288,167 @@ class Doctor
|
|
|
286
288
|
# content scanning. check_global_store (above) is store/full-scope and includes
|
|
287
289
|
# orphaned_intents / ghost_references, both explicitly forbidden at core by D1.
|
|
288
290
|
|
|
291
|
+
# Row E (spec D8, spec 315b): #check_core_files's own `version_match` only ever
|
|
292
|
+
# compares the SELECTED harness's `<dir>/plastic/VERSION` against the global
|
|
293
|
+
# VERSION, so a second installed harness left behind on an old version is never
|
|
294
|
+
# version-checked at all -- exactly how ten stale 1.14.1 Codex registrations
|
|
295
|
+
# survived a `pass`. This runs the same comparison for EVERY installed harness
|
|
296
|
+
# (agent_dir on disk), named `version_match_<key>` so the existing `version_match`
|
|
297
|
+
# name and position stay reserved for the selected harness (pinned tests:
|
|
298
|
+
# test/doctor_test.rb:1846,1861,1873). Full tier only (`run_checks`); never
|
|
299
|
+
# `run_core_checks`, which is `binary: true` and runs on the session-start boot
|
|
300
|
+
# path, where a second-harness warn would become a boot-time error for every user.
|
|
301
|
+
def check_harness_versions
|
|
302
|
+
global_version = read_version
|
|
303
|
+
return [] unless global_version
|
|
304
|
+
|
|
305
|
+
agents.filter_map do |key, config|
|
|
306
|
+
next unless config.is_a?(Hash) && File.directory?(config[:dir].to_s)
|
|
307
|
+
|
|
308
|
+
agent_version_path = File.join(config[:dir], "plastic", "VERSION")
|
|
309
|
+
name = "version_match_#{key}"
|
|
310
|
+
|
|
311
|
+
if !File.exist?(agent_version_path)
|
|
312
|
+
check(
|
|
313
|
+
category: "core_files", name: name, status: "warn",
|
|
314
|
+
message: "#{config[:name]}'s agent-side VERSION file not found at #{tilde(agent_version_path)}",
|
|
315
|
+
fixable: true,
|
|
316
|
+
fix_hint: "Re-sync the stale harness: npx @zalom/plastic@latest install --reinstall <flag>, or plastic-rollback to a prior version"
|
|
317
|
+
)
|
|
318
|
+
else
|
|
319
|
+
agent_version = File.read(agent_version_path).strip
|
|
320
|
+
if global_version == agent_version
|
|
321
|
+
check(
|
|
322
|
+
category: "core_files", name: name, status: "pass",
|
|
323
|
+
message: "Global VERSION (#{global_version}) matches #{config[:name]}'s agent-side VERSION"
|
|
324
|
+
)
|
|
325
|
+
else
|
|
326
|
+
check(
|
|
327
|
+
category: "core_files", name: name, status: "warn",
|
|
328
|
+
message: "Version mismatch for #{config[:name]}: global=#{global_version}, agent=#{agent_version}",
|
|
329
|
+
details: [
|
|
330
|
+
"#{tilde(File.join(plastic_home, "VERSION"))}: #{global_version}",
|
|
331
|
+
"#{tilde(agent_version_path)}: #{agent_version}",
|
|
332
|
+
],
|
|
333
|
+
fixable: true,
|
|
334
|
+
fix_hint: "Re-sync the stale harness: npx @zalom/plastic@latest install --reinstall <flag>, or plastic-rollback to a prior version"
|
|
335
|
+
)
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# The Codex hook NAME expected per event, keyed off HookRegistry's own
|
|
342
|
+
# constants rather than a full built command string: naming it, not the
|
|
343
|
+
# literal dispatcher path, is what #check_codex_stale_registrations needs,
|
|
344
|
+
# so this never depends on plastic_home resolving to the same install the
|
|
345
|
+
# live hooks.json's commands were written under.
|
|
346
|
+
def codex_expected_names_by_event
|
|
347
|
+
names = {}
|
|
348
|
+
post_order = HookRegistry.events["PostToolUse"].flat_map { |g| g["hooks"].map { |h| h["name"] } }
|
|
349
|
+
names["PostToolUse"] = HookRegistry::CODEX_POST_HOOKS & post_order
|
|
350
|
+
|
|
351
|
+
HookRegistry::CODEX_LIVE_STATE_EVENTS.each do |event|
|
|
352
|
+
names[event] = HookRegistry.events[event].flat_map { |g| g["hooks"].map { |h| h["name"] } }
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
end_order = HookRegistry.events["SessionEnd"].flat_map { |g| g["hooks"].map { |h| h["name"] } }
|
|
356
|
+
names["SessionEnd"] = HookRegistry::CODEX_SESSION_END_HOOKS & end_order
|
|
357
|
+
names
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Row E (spec D8, spec 315b): #codex_hooks_registered_check computes
|
|
361
|
+
# `want - got` and iterates `expected.each`, so it can see a MISSING registration
|
|
362
|
+
# but never an EXTRA one, and it can never even visit an event `expected` does not
|
|
363
|
+
# list at all (a retired event such as PreToolUse, which a stale ~/.codex/hooks.json
|
|
364
|
+
# can still carry). This scans the UNION of expected and live event keys instead, so
|
|
365
|
+
# a stale registration parked in a retired event is visible. Compares hook NAMES
|
|
366
|
+
# (see #codex_expected_names_by_event), not full command strings: a full-command
|
|
367
|
+
# comparison would embed this Doctor instance's own `plastic_home` in the expected
|
|
368
|
+
# dispatcher path, which is only guaranteed to match the live hooks.json's own
|
|
369
|
+
# dispatcher path in a real, single install, never a test that fakes one without the
|
|
370
|
+
# other. Full tier only (`run_checks`); never `run_core_checks` (D8).
|
|
371
|
+
#
|
|
372
|
+
# Post-execution review item 5: name-only comparison alone is blind to two real
|
|
373
|
+
# cases, both closed here without reintroducing any plastic_home coupling: (a) the
|
|
374
|
+
# SAME (event, name) pair registered more than once (each copy's name is
|
|
375
|
+
# individually expected, so a "not in the expected set" scan never sees the
|
|
376
|
+
# duplicate), and (b) a correctly-named entry whose dispatcher path is an OLD
|
|
377
|
+
# install, different from the path every OTHER Plastic entry in this same file
|
|
378
|
+
# actually uses -- the "correct" path here is whichever path the file's own
|
|
379
|
+
# majority of entries already agrees on, never a path this Doctor instance derives
|
|
380
|
+
# from its own plastic_home.
|
|
381
|
+
def check_codex_stale_registrations
|
|
382
|
+
config = agents["codex"]
|
|
383
|
+
return [] unless config.is_a?(Hash) && File.directory?(config[:dir].to_s)
|
|
384
|
+
|
|
385
|
+
home_dir = config[:home_dir] || config[:dir]
|
|
386
|
+
hooks_json = File.join(home_dir, "hooks.json")
|
|
387
|
+
data = read_json_safe(hooks_json)
|
|
388
|
+
return [] if data.nil? || !data.is_a?(Hash)
|
|
389
|
+
|
|
390
|
+
expected_names = codex_expected_names_by_event
|
|
391
|
+
live = data["hooks"].is_a?(Hash) ? data["hooks"] : {}
|
|
392
|
+
|
|
393
|
+
# One pass over every live Plastic entry (event, hook name, and the literal
|
|
394
|
+
# dispatcher-path token it actually invokes), shared by all three checks below.
|
|
395
|
+
entries = []
|
|
396
|
+
(expected_names.keys | live.keys).each do |event|
|
|
397
|
+
Array(live[event]).each do |group|
|
|
398
|
+
Array(group["hooks"]).each do |h|
|
|
399
|
+
cmd = h["command"]
|
|
400
|
+
next unless HookRegistry.codex_purge_command?(cmd)
|
|
401
|
+
|
|
402
|
+
dispatcher_path = cmd.to_s.split(/\s+/).reject(&:empty?).first.to_s.delete("\"'")
|
|
403
|
+
name = HookRegistry.command_basenames(cmd).last
|
|
404
|
+
entries << { event: event, name: name, dispatcher_path: dispatcher_path, cmd: cmd }
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
stale = []
|
|
410
|
+
|
|
411
|
+
# Not in the expected name set for this event at all (the original check).
|
|
412
|
+
entries.each do |e|
|
|
413
|
+
want_names = Array(expected_names[e[:event]])
|
|
414
|
+
stale << "#{e[:event]}: #{e[:cmd]}" unless want_names.include?(e[:name])
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
# (a) the same (event, name) pair registered more than once.
|
|
418
|
+
entries.group_by { |e| [e[:event], e[:name]] }.each_value do |group|
|
|
419
|
+
next if group.size <= 1
|
|
420
|
+
|
|
421
|
+
group.each { |e| stale << "#{e[:event]}: #{e[:cmd]} (duplicate registration of #{e[:name]})" }
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# (b) a dispatcher path that differs from the path every other Plastic entry in
|
|
425
|
+
# this same file actually uses.
|
|
426
|
+
unless entries.empty?
|
|
427
|
+
majority_path = entries.map { |e| e[:dispatcher_path] }.tally.max_by { |(_path, count)| count }&.first
|
|
428
|
+
entries.each do |e|
|
|
429
|
+
next if e[:dispatcher_path] == majority_path
|
|
430
|
+
|
|
431
|
+
stale << "#{e[:event]}: #{e[:cmd]} (dispatcher path #{e[:dispatcher_path]} differs from " \
|
|
432
|
+
"this file's other Plastic entries at #{majority_path})"
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
stale.uniq!
|
|
437
|
+
|
|
438
|
+
if stale.empty?
|
|
439
|
+
[check(
|
|
440
|
+
category: "agent_registration", name: "codex_stale_registrations", status: "pass",
|
|
441
|
+
message: "No stale Plastic Codex registrations found outside the expected hook set"
|
|
442
|
+
)]
|
|
443
|
+
else
|
|
444
|
+
[check(
|
|
445
|
+
category: "agent_registration", name: "codex_stale_registrations", status: "warn",
|
|
446
|
+
message: "#{stale.size} stale Codex registration(s) found outside the expected hook set",
|
|
447
|
+
details: stale, fixable: true,
|
|
448
|
+
fix_hint: "Re-run the Plastic installer with --codex --reinstall to purge stale entries"
|
|
449
|
+
)]
|
|
450
|
+
end
|
|
451
|
+
end
|
|
289
452
|
# --- Check category 2: Conventions ---
|
|
290
453
|
|
|
291
454
|
# When `scopes` is a non-nil Array of scope strings (e.g. ["global"] or
|
|
@@ -431,7 +594,7 @@ class Doctor
|
|
|
431
594
|
message: "#{bad_sections.size} intent file(s) have non-sanctioned ## sections",
|
|
432
595
|
details: bad_sections.map { |b| "#{b[:dir]}: #{b[:issues].join(", ")}" },
|
|
433
596
|
fixable: true,
|
|
434
|
-
fix_hint: "
|
|
597
|
+
fix_hint: "Relocate each unsanctioned section into the " \
|
|
435
598
|
"intent's revisions.md via move-and-record (a missing required section is restored " \
|
|
436
599
|
"or reprojected instead); see plastic-conventions > references/maintenance-and-revisions.md"
|
|
437
600
|
)
|
|
@@ -553,9 +716,9 @@ class Doctor
|
|
|
553
716
|
# suppress) is exactly what makes the row dead.
|
|
554
717
|
def done_signal_findings_for_dir(dir, label:, scope:, dirname:, terminal:, active:, excluded_rules: [])
|
|
555
718
|
outcome = File.join(dir, "outcome.md")
|
|
556
|
-
outcome_real =
|
|
719
|
+
outcome_real = Savepoint.stage_file_present?(outcome)
|
|
557
720
|
findings = { conflict: nil, phantom: nil, gap: [], operational_gap: [], excluded: [],
|
|
558
|
-
excluded_rules_fired: [], stalled: nil }
|
|
721
|
+
excluded_rules_fired: [], stalled: nil, unbackfilled: [], excluded_backfill: [] }
|
|
559
722
|
|
|
560
723
|
# HARD conflict: the deliverable exists but INDEX still says Active. This
|
|
561
724
|
# is the one true INDEX-wins disagreement, so it stays a fail.
|
|
@@ -569,7 +732,7 @@ def done_signal_findings_for_dir(dir, label:, scope:, dirname:, terminal:, activ
|
|
|
569
732
|
# the generic replacement for the frozen 170a amnesty list is simply "never suppress" -
|
|
570
733
|
# the message already labels a terminal phantom report-only, so dropping the id-based
|
|
571
734
|
# suppression is strictly more general and needs no per-store state at all).
|
|
572
|
-
phantom_lines =
|
|
735
|
+
phantom_lines = Savepoint.savepoint_phantom_lines(dir)
|
|
573
736
|
if phantom_lines.any?
|
|
574
737
|
detail = phantom_lines.map { |line, reason| "#{line} (#{reason})" }.join("; ")
|
|
575
738
|
scope_note = terminal ? "terminal in INDEX, report-only (immutable history)" : "live intent, auto-rebuildable"
|
|
@@ -583,7 +746,7 @@ def done_signal_findings_for_dir(dir, label:, scope:, dirname:, terminal:, activ
|
|
|
583
746
|
if terminal && !outcome_real
|
|
584
747
|
state = File.exist?(outcome) ? "still a placeholder" : "missing"
|
|
585
748
|
findings[:gap] << "#{label}: terminal in INDEX but outcome.md is #{state} " \
|
|
586
|
-
"(delivery claim -
|
|
749
|
+
"(delivery claim; written at close by end-intent since intent 308)"
|
|
587
750
|
end
|
|
588
751
|
|
|
589
752
|
if terminal
|
|
@@ -603,6 +766,21 @@ def done_signal_findings_for_dir(dir, label:, scope:, dirname:, terminal:, activ
|
|
|
603
766
|
end
|
|
604
767
|
findings[:excluded_rules_fired] << "savepoint_operational" if suppressed && findings[:excluded].any?
|
|
605
768
|
|
|
769
|
+
# Unbackfilled documents (intent 308): spec.md or plan.md missing or still the
|
|
770
|
+
# placeholder, or no real action file, on a terminal intent. Every one of these is
|
|
771
|
+
# written from the record by `scaffold-intent backfill`, so this is repairable and
|
|
772
|
+
# reported as a fixable warn (backfilled_complete). Its exclusions go to their OWN
|
|
773
|
+
# bucket so savepoint_operational's consumed/dead-row bookkeeping above never sees them.
|
|
774
|
+
backfill_gaps = %w[spec.md plan.md].reject { |f| Savepoint.stage_file_present?(File.join(dir, f)) }
|
|
775
|
+
backfill_gaps << "actions/" unless Savepoint.has_real_action?(dir)
|
|
776
|
+
if backfill_gaps.any?
|
|
777
|
+
suppressed_backfill = excluded_rules.include?("backfilled_complete")
|
|
778
|
+
target = suppressed_backfill ? findings[:excluded_backfill] : findings[:unbackfilled]
|
|
779
|
+
target << "#{label}: terminal in INDEX but #{backfill_gaps.join(", ")} " \
|
|
780
|
+
"#{backfill_gaps.size == 1 ? "is" : "are"} missing or still a placeholder (backfillable)"
|
|
781
|
+
findings[:excluded_rules_fired] << "backfilled_complete" if suppressed_backfill
|
|
782
|
+
end
|
|
783
|
+
|
|
606
784
|
# Stalled completion: unchanged, never consulted amnesty.
|
|
607
785
|
if File.exist?(Lock.path(dir))
|
|
608
786
|
note = Lock.fresh?(dir) ? "delivery.lock still present (post-done window not closed)"
|
|
@@ -626,6 +804,9 @@ def check_done_signals(scopes: nil)
|
|
|
626
804
|
dead_row_paths = []
|
|
627
805
|
stalled = []
|
|
628
806
|
phantoms = []
|
|
807
|
+
unbackfilled = [] # spec/plan/actions gaps on terminal intents (intent 308) - repairable
|
|
808
|
+
excluded_backfill = [] # backfill gaps knowingly exempted via doctor-exclusions (intent 308)
|
|
809
|
+
dead_rows_by_rule = Hash.new { |h, k| h[k] = [] }
|
|
629
810
|
|
|
630
811
|
done_signal_stores(scopes).each do |store|
|
|
631
812
|
exclusions = DoctorExclusions.load(store[:index])
|
|
@@ -634,7 +815,7 @@ def check_done_signals(scopes: nil)
|
|
|
634
815
|
exclusion_error_paths << exclusions[:path]
|
|
635
816
|
end
|
|
636
817
|
|
|
637
|
-
consumed = { "savepoint_operational" => [] }
|
|
818
|
+
consumed = { "savepoint_operational" => [], "backfilled_complete" => [] }
|
|
638
819
|
# `known_ids` (post-review fix): every intent id with a REAL DIRECTORY in this store, scanned
|
|
639
820
|
# directly from disk - independent of INDEX.md. An id can have a directory on disk without
|
|
640
821
|
# being listed in INDEX (a de-indexed "ghost"), and the walk below alone would never visit it;
|
|
@@ -672,6 +853,11 @@ def check_done_signals(scopes: nil)
|
|
|
672
853
|
phantoms << findings[:phantom] if findings[:phantom]
|
|
673
854
|
gaps.concat(findings[:gap])
|
|
674
855
|
operational_gaps.concat(findings[:operational_gap])
|
|
856
|
+
unbackfilled.concat(findings[:unbackfilled])
|
|
857
|
+
if findings[:excluded_backfill].any?
|
|
858
|
+
excluded_backfill.concat(findings[:excluded_backfill])
|
|
859
|
+
exclusion_paths << exclusions[:path]
|
|
860
|
+
end
|
|
675
861
|
if findings[:excluded].any?
|
|
676
862
|
excluded.concat(findings[:excluded])
|
|
677
863
|
exclusion_paths << exclusions[:path]
|
|
@@ -692,7 +878,9 @@ def check_done_signals(scopes: nil)
|
|
|
692
878
|
else
|
|
693
879
|
"names an intent with no current #{row[:rule]} finding"
|
|
694
880
|
end
|
|
695
|
-
|
|
881
|
+
dead_row = "#{store[:scope]}: #{exclusions[:path]}: #{row[:rule]} #{row[:id]} - #{reason}"
|
|
882
|
+
dead_rows << dead_row
|
|
883
|
+
dead_rows_by_rule[row[:rule]] << dead_row
|
|
696
884
|
dead_row_paths << exclusions[:path]
|
|
697
885
|
end
|
|
698
886
|
end
|
|
@@ -733,7 +921,7 @@ def check_done_signals(scopes: nil)
|
|
|
733
921
|
checks << check(
|
|
734
922
|
category: "done_signals", name: "signals_complete", status: "pass",
|
|
735
923
|
message: "#{gaps.size} terminal intent#{gaps.size == 1 ? "" : "s"} missing a real outcome.md " \
|
|
736
|
-
"(delivery claim -
|
|
924
|
+
"(delivery claim; end-intent writes outcome.md at close since intent 308, so this is pre-308 history or a close outside end-intent; informational only, does not affect doctor's exit code)",
|
|
737
925
|
details: gaps
|
|
738
926
|
)
|
|
739
927
|
end
|
|
@@ -750,10 +938,19 @@ def check_done_signals(scopes: nil)
|
|
|
750
938
|
# suppressed nothing this run. It is purely informational, exactly like `exclusion_suffix` - it
|
|
751
939
|
# never changes status on any of the three branches below, because a stale governance-record row
|
|
752
940
|
# is bookkeeping drift, not a store regression (219 D6 is untouched: no disposition is invented).
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
941
|
+
# Per rule (intent 308): savepoint_operational and backfilled_complete each fold in only
|
|
942
|
+
# their own exclusions and dead rows, so one check never carries the other's counts.
|
|
943
|
+
suffixes = lambda do |excluded_rows, dead|
|
|
944
|
+
ex = excluded_rows.empty? ? "" : " (#{excluded_rows.size} excluded via #{exclusion_paths.join(", ")})"
|
|
945
|
+
dd = dead.empty? ? "" : " (#{dead.size} dead row#{dead.size == 1 ? "" : "s"} " \
|
|
946
|
+
"in #{dead_row_paths.join(", ")}, suppressing nothing - prune with " \
|
|
947
|
+
"`maintenance-run --tool register-exclusions --prune`)"
|
|
948
|
+
[ex, dd]
|
|
949
|
+
end
|
|
950
|
+
savepoint_dead = dead_rows_by_rule["savepoint_operational"]
|
|
951
|
+
backfill_dead = dead_rows_by_rule["backfilled_complete"]
|
|
952
|
+
exclusion_suffix, dead_suffix = suffixes.call(excluded, savepoint_dead)
|
|
953
|
+
backfill_exclusion_suffix, backfill_dead_suffix = suffixes.call(excluded_backfill, backfill_dead)
|
|
757
954
|
|
|
758
955
|
if exclusion_errors.any?
|
|
759
956
|
checks << check(
|
|
@@ -762,7 +959,7 @@ def check_done_signals(scopes: nil)
|
|
|
762
959
|
"missing an operational savepoint.md or its Done echo, and " \
|
|
763
960
|
"#{exclusion_errors.size} doctor-exclusions error#{exclusion_errors.size == 1 ? "" : "s"} " \
|
|
764
961
|
"(a malformed exclusion file never suppresses a finding)#{exclusion_suffix}#{dead_suffix}",
|
|
765
|
-
details: operational_gaps + exclusion_errors +
|
|
962
|
+
details: operational_gaps + exclusion_errors + savepoint_dead, fixable: true,
|
|
766
963
|
fix_hint: "Fix the malformed doctor-exclusions file(s) (#{exclusion_error_paths.join(", ")}) - " \
|
|
767
964
|
"format `rule_name id id id`, blank lines and # comments ignored - then reconstruct " \
|
|
768
965
|
"any remaining real gap via `maintenance-run --tool rebuild-savepoint --intent <id> " \
|
|
@@ -774,7 +971,7 @@ def check_done_signals(scopes: nil)
|
|
|
774
971
|
category: "done_signals", name: "savepoint_operational", status: "pass",
|
|
775
972
|
message: "No terminal intent is missing an operational savepoint.md or its Done echo" \
|
|
776
973
|
"#{exclusion_suffix}#{dead_suffix}",
|
|
777
|
-
details:
|
|
974
|
+
details: savepoint_dead
|
|
778
975
|
)
|
|
779
976
|
else
|
|
780
977
|
checks << check(
|
|
@@ -782,13 +979,50 @@ def check_done_signals(scopes: nil)
|
|
|
782
979
|
message: "#{operational_gaps.size} terminal intent#{operational_gaps.size == 1 ? "" : "s"} " \
|
|
783
980
|
"missing an operational savepoint.md or its Done echo (reconstructible)" \
|
|
784
981
|
"#{exclusion_suffix}#{dead_suffix}",
|
|
785
|
-
details: operational_gaps +
|
|
982
|
+
details: operational_gaps + savepoint_dead, fixable: true,
|
|
786
983
|
fix_hint: "Reconstruct the minimal two-line started/Done echo via " \
|
|
787
984
|
"`maintenance-run --tool rebuild-savepoint --intent <id> --apply` (197-conformant: " \
|
|
788
985
|
"receipt-before-write via RevisionsWriter, one intent per invocation, owner-approval-gated)."
|
|
789
986
|
)
|
|
790
987
|
end
|
|
791
988
|
|
|
989
|
+
# backfilled_complete (intent 308): spec.md, plan.md, or a real action file missing on a
|
|
990
|
+
# terminal intent. Same three branches as savepoint_operational: a malformed exclusion
|
|
991
|
+
# file is always loud, a clean set passes with its own exclusion and dead-row counts
|
|
992
|
+
# folded in, a real gap set warns with the backfill verb as the fix.
|
|
993
|
+
backfill_hint = "Write the missing documents from the record via " \
|
|
994
|
+
"`scaffold-intent backfill --store <store> --id <id> --disposition " \
|
|
995
|
+
"<delivered|abandoned>` (never touches real content, one intent per invocation)."
|
|
996
|
+
if exclusion_errors.any?
|
|
997
|
+
checks << check(
|
|
998
|
+
category: "done_signals", name: "backfilled_complete", status: "warn",
|
|
999
|
+
message: "#{unbackfilled.size} terminal intent#{unbackfilled.size == 1 ? "" : "s"} " \
|
|
1000
|
+
"missing a backfillable document, and #{exclusion_errors.size} doctor-exclusions " \
|
|
1001
|
+
"error#{exclusion_errors.size == 1 ? "" : "s"} (a malformed exclusion file never " \
|
|
1002
|
+
"suppresses a finding)#{backfill_exclusion_suffix}#{backfill_dead_suffix}",
|
|
1003
|
+
details: unbackfilled + exclusion_errors + backfill_dead, fixable: true,
|
|
1004
|
+
fix_hint: "Fix the malformed doctor-exclusions file(s) (#{exclusion_error_paths.join(", ")}), " \
|
|
1005
|
+
"then write the missing documents from the record via `scaffold-intent backfill " \
|
|
1006
|
+
"--store <store> --id <id> --disposition <delivered|abandoned>`."
|
|
1007
|
+
)
|
|
1008
|
+
elsif unbackfilled.empty?
|
|
1009
|
+
checks << check(
|
|
1010
|
+
category: "done_signals", name: "backfilled_complete", status: "pass",
|
|
1011
|
+
message: "Every terminal intent carries a real spec.md, plan.md, and action file" \
|
|
1012
|
+
"#{backfill_exclusion_suffix}#{backfill_dead_suffix}",
|
|
1013
|
+
details: backfill_dead
|
|
1014
|
+
)
|
|
1015
|
+
else
|
|
1016
|
+
checks << check(
|
|
1017
|
+
category: "done_signals", name: "backfilled_complete", status: "warn",
|
|
1018
|
+
message: "#{unbackfilled.size} terminal intent#{unbackfilled.size == 1 ? "" : "s"} " \
|
|
1019
|
+
"missing a backfillable document (spec.md, plan.md, or a real action file)" \
|
|
1020
|
+
"#{backfill_exclusion_suffix}#{backfill_dead_suffix}",
|
|
1021
|
+
details: unbackfilled + backfill_dead, fixable: true,
|
|
1022
|
+
fix_hint: backfill_hint
|
|
1023
|
+
)
|
|
1024
|
+
end
|
|
1025
|
+
|
|
792
1026
|
if stalled.empty?
|
|
793
1027
|
checks << check(
|
|
794
1028
|
category: "done_signals", name: "stalled_completion", status: "pass",
|
|
@@ -818,8 +1052,8 @@ def check_done_signals(scopes: nil)
|
|
|
818
1052
|
message: "#{phantoms.size} intent#{phantoms.size == 1 ? "" : "s"} carry savepoint.md " \
|
|
819
1053
|
"line(s) contradicted by disk (advisory; terminal history stays report-only)",
|
|
820
1054
|
details: phantoms, fixable: true,
|
|
821
|
-
fix_hint: "For a live (Active) intent,
|
|
822
|
-
"
|
|
1055
|
+
fix_hint: "For a live (Active) intent, rebuild the ledger via " \
|
|
1056
|
+
"Savepoint.rebuild_savepoint. Terminal (Completed/Abandoned) intents are immutable: " \
|
|
823
1057
|
"a phantom there stays advisory unless an explicit human grant authorizes the " \
|
|
824
1058
|
"124a manual Done-bookend repair."
|
|
825
1059
|
)
|
|
@@ -991,9 +1225,9 @@ end
|
|
|
991
1225
|
INTENT_END_LIFECYCLE_FILES = %w[spec.md plan.md checklist.md outcome.md].freeze
|
|
992
1226
|
|
|
993
1227
|
def intent_lifecycle_artifacts_check(intent_dir, disposition)
|
|
994
|
-
missing = INTENT_END_LIFECYCLE_FILES.select { |f| !
|
|
995
|
-
unless
|
|
996
|
-
missing = [File.basename(
|
|
1228
|
+
missing = INTENT_END_LIFECYCLE_FILES.select { |f| !Savepoint.stage_file_present?(File.join(intent_dir, f)) }
|
|
1229
|
+
unless Savepoint.stage_file_present?(Savepoint.intent_file(intent_dir))
|
|
1230
|
+
missing = [File.basename(Savepoint.intent_file(intent_dir))] + missing
|
|
997
1231
|
end
|
|
998
1232
|
|
|
999
1233
|
outcome_note = nil
|
|
@@ -1014,7 +1248,7 @@ end
|
|
|
1014
1248
|
|
|
1015
1249
|
def intent_checklist_complete_check(intent_dir)
|
|
1016
1250
|
path = File.join(intent_dir, "checklist.md")
|
|
1017
|
-
unless
|
|
1251
|
+
unless Savepoint.stage_file_present?(path)
|
|
1018
1252
|
return check(category: "intent_end", name: "intent_checklist_complete", status: "pass",
|
|
1019
1253
|
message: "n/a: checklist.md absent or placeholder (flagged above if that is a gap)")
|
|
1020
1254
|
end
|
|
@@ -1074,7 +1308,8 @@ end
|
|
|
1074
1308
|
# Terminal-gated (281 D3): done_signal_findings_for_dir only ever produces this finding
|
|
1075
1309
|
# inside `if terminal`, so honoring the exclusion for a still-Active intent would suppress a
|
|
1076
1310
|
# strictly larger set of facts than the rule id names - and would let a mistyped id silence
|
|
1077
|
-
# the live, repairable warning scripts/end-intent's
|
|
1311
|
+
# the live, repairable warning scripts/end-intent's structure self-check exists to raise
|
|
1312
|
+
# (a report, never a refusal, since intent 308).
|
|
1078
1313
|
#
|
|
1079
1314
|
# Never raises: DoctorExclusions is fail-open by contract (274 D5) and index_sections_by_dir
|
|
1080
1315
|
# returns an empty map for a missing INDEX.
|
|
@@ -1131,9 +1366,9 @@ end
|
|
|
1131
1366
|
first_line = File.read(savepoint).each_line.find { |l| !l.strip.empty? }.to_s.strip
|
|
1132
1367
|
parts = first_line.split(/\s{2,}/)
|
|
1133
1368
|
born_pair = parts.length >= 3 ? [parts[1], parts[2]] : nil
|
|
1134
|
-
expected_pair =
|
|
1369
|
+
expected_pair = Savepoint.savepoint_milestone(intent_dir, File.basename(Savepoint.intent_file(intent_dir)))
|
|
1135
1370
|
|
|
1136
|
-
phantoms =
|
|
1371
|
+
phantoms = Savepoint.savepoint_phantom_lines(intent_dir)
|
|
1137
1372
|
problems = []
|
|
1138
1373
|
problems << "born line #{born_pair.inspect} does not match the expected #{expected_pair.inspect}" \
|
|
1139
1374
|
if born_pair != expected_pair
|
|
@@ -1147,7 +1382,7 @@ end
|
|
|
1147
1382
|
check(category: "intent_end", name: "intent_savepoint_truthful", status: "warn",
|
|
1148
1383
|
message: "#{problems.size} savepoint truthfulness issue(s) (advisory, never blocking)",
|
|
1149
1384
|
details: problems,
|
|
1150
|
-
fixable: true, fix_hint: "
|
|
1385
|
+
fixable: true, fix_hint: "Rebuild the ledger via Savepoint.rebuild_savepoint")
|
|
1151
1386
|
end
|
|
1152
1387
|
end
|
|
1153
1388
|
|
|
@@ -1270,7 +1505,7 @@ end
|
|
|
1270
1505
|
checks << graph_finding_check(
|
|
1271
1506
|
"graph_i4_danglers", i4,
|
|
1272
1507
|
"Every sources/chain id resolves to a real intent (I4)",
|
|
1273
|
-
"
|
|
1508
|
+
"Record the dangling sources/chain edge as a " \
|
|
1274
1509
|
"broken-source/broken-chain move-and-record entry in the intent's revisions.md (see " \
|
|
1275
1510
|
"plastic-conventions > references/maintenance-and-revisions.md), or restore the missing intent"
|
|
1276
1511
|
)
|
|
@@ -1297,18 +1532,6 @@ end
|
|
|
1297
1532
|
|
|
1298
1533
|
|
|
1299
1534
|
|
|
1300
|
-
# claude_hooks_implemented (intent 244, the Claude twin of intent 200's Codex
|
|
1301
|
-
# check): the edit-path gates now live as branches inside one dispatcher,
|
|
1302
|
-
# which is exactly the shape that let links-gate ship registered and dead on
|
|
1303
|
-
# Codex. HookRegistry::GATE_TOOLS is the registry side; scripts/hook-edit-gates
|
|
1304
|
-
# is the implementation side. Checked in BOTH directions, so a registered gate
|
|
1305
|
-
# with no branch (always allows, silently) and a branch nobody registers
|
|
1306
|
-
# (dead code) are both reported.
|
|
1307
|
-
#
|
|
1308
|
-
# Read as plain text, never required: the dispatcher has top-level side effects
|
|
1309
|
-
# (it reads $stdin and exits), the same reason codex_dispatcher_gate_names reads
|
|
1310
|
-
# scripts/codex-hook as text.
|
|
1311
|
-
|
|
1312
1535
|
# Plastic skills install as ~/.claude/skills/plastic-<name>/SKILL.md. Pass if at
|
|
1313
1536
|
# least one such skill is present.
|
|
1314
1537
|
|
|
@@ -1357,7 +1580,7 @@ end
|
|
|
1357
1580
|
# dispatcher is an executable script with real top-level side effects (it reads
|
|
1358
1581
|
# $stdin and may exit), so it can never be required or executed to introspect it,
|
|
1359
1582
|
# only read as plain text, mirroring codex_agent_toml_well_formed? above. Pulls
|
|
1360
|
-
#
|
|
1583
|
+
# hook names from the STATE_HOOKS %w[] literal, plus the `when
|
|
1361
1584
|
# "<name>"` labels of the top-level `case gate` statement (stopping at its
|
|
1362
1585
|
# trailing `else`). Line-shape dependent, not AST-safe, disclosed as such in
|
|
1363
1586
|
# docs; the healthy-install pass test against the REAL dispatcher is what proves
|
|
@@ -1407,7 +1630,7 @@ end
|
|
|
1407
1630
|
# Classification per installed agent basename, checked in this order:
|
|
1408
1631
|
# 1. an `agents.models.<basename>` override IS configured -> sanctioned,
|
|
1409
1632
|
# pass/informational, LISTED regardless of whether frontmatter matches
|
|
1410
|
-
# (that mismatch is the override working, e.g. plastic-
|
|
1633
|
+
# (that mismatch is the override working, e.g. plastic-executor: fable).
|
|
1411
1634
|
# 2. no override AND basename is a TIER_DEFAULTS key -> compare frontmatter
|
|
1412
1635
|
# to that default; match is pass (clean), mismatch is real drift (warn).
|
|
1413
1636
|
# 3. no override AND basename is a CONSULTATION_AGENTS member -> not a
|
|
@@ -2173,11 +2396,14 @@ end
|
|
|
2173
2396
|
all_checks += check_conventions(scopes: ["global"])
|
|
2174
2397
|
all_checks += check_agent_registration(agent_key)
|
|
2175
2398
|
all_checks += check_core_files(agent_key)
|
|
2399
|
+
all_checks += check_harness_versions
|
|
2400
|
+
all_checks += check_codex_stale_registrations
|
|
2176
2401
|
all_checks += check_deprecations
|
|
2177
2402
|
all_checks += check_config_asks(agent_key)
|
|
2178
2403
|
all_checks += check_qmd
|
|
2179
2404
|
all_checks += check_ruby_runtime
|
|
2180
2405
|
all_checks += check_done_signals(scopes: ["global"])
|
|
2406
|
+
all_checks += check_session_ledger(scopes: ["global"])
|
|
2181
2407
|
all_checks += check_skill_lint
|
|
2182
2408
|
all_checks += check_install_integrity
|
|
2183
2409
|
|
|
@@ -2228,10 +2454,10 @@ end
|
|
|
2228
2454
|
case store
|
|
2229
2455
|
when :all
|
|
2230
2456
|
check_global_store + check_project_stores + check_conventions + check_done_signals +
|
|
2231
|
-
check_qmd(detector: qmd_detector, runner: qmd_runner)
|
|
2457
|
+
check_session_ledger + check_qmd(detector: qmd_detector, runner: qmd_runner)
|
|
2232
2458
|
when :global
|
|
2233
2459
|
check_global_store + check_conventions(scopes: ["global"]) +
|
|
2234
|
-
check_done_signals(scopes: ["global"]) +
|
|
2460
|
+
check_done_signals(scopes: ["global"]) + check_session_ledger(scopes: ["global"]) +
|
|
2235
2461
|
check_qmd(detector: qmd_detector, runner: qmd_runner, collection: "plastic-global")
|
|
2236
2462
|
else
|
|
2237
2463
|
all_checks_for_project_slug(store, qmd_detector: qmd_detector, qmd_runner: qmd_runner,
|