Remediate cc-architect audit findings across os-* plugins (#75-#79)
- os-context: audit-sessions rubric updated to ADR-0042 git-issues-only boundary (#75) - os-backlog: drop dead Planka Config#board/#configured?, retarget tests; record ADR-0025 exemption for bin/wakeup-poll in plugin CLAUDE.md (#76) - os-vault: align hooks/config.py default to graphify-out; refresh stale eval/README.md WS2 status (#77) - gitignore .pytest_cache/ (#78) - cc-architect: plugin_config resolves actual marketplace from installed_plugins.json instead of assuming cc-os (#79) Opus-reviewed PASS; os-backlog 85 runs / cc-architect script suites green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CTE1yYvTEg1cJZBhKNRZvL
This commit is contained in:
parent
f2fe45bab8
commit
cc2f2914c5
|
|
@ -16,6 +16,7 @@ graphify-out/
|
||||||
|
|
||||||
# Python bytecode
|
# Python bytecode
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
# autoresearch skill run logs (eval iterations)
|
# autoresearch skill run logs (eval iterations)
|
||||||
/autoresearch/
|
/autoresearch/
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,23 @@ module PluginConfig
|
||||||
private
|
private
|
||||||
|
|
||||||
def plugin_key
|
def plugin_key
|
||||||
"#{plugin}@#{marketplace}"
|
"#{plugin}@#{resolved_marketplace}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# The marketplace id this plugin is actually installed under, per
|
||||||
|
# installed_plugins.json, falling back to the --marketplace param when
|
||||||
|
# no installed entry exists yet (e.g. before first install). Needed
|
||||||
|
# because cc-os's os-* plugins install under a `local-plugins`
|
||||||
|
# marketplace (symlink into ~/.claude/plugins) rather than whatever
|
||||||
|
# marketplace id the caller assumes (e.g. the repo's own `cc-os`),
|
||||||
|
# which otherwise produces false "not installed" results.
|
||||||
|
def resolved_marketplace
|
||||||
|
data = read_json(installed_plugins_path)
|
||||||
|
if data && data['plugins']
|
||||||
|
match = data['plugins'].keys.find { |k| k.start_with?("#{plugin}@") }
|
||||||
|
return match.split('@', 2).last if match
|
||||||
|
end
|
||||||
|
marketplace
|
||||||
end
|
end
|
||||||
|
|
||||||
def read_json(path)
|
def read_json(path)
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,20 @@ see NOTE below.
|
||||||
NOTE (2026-07-16): a major rework retiring Planka in favor of git-issues-only
|
NOTE (2026-07-16): a major rework retiring Planka in favor of git-issues-only
|
||||||
(ADR-0042, OpenSpec change retire-planka-git-issues-only) is in flight on main;
|
(ADR-0042, OpenSpec change retire-planka-git-issues-only) is in flight on main;
|
||||||
this index intentionally avoids enumerating internals that rework replaces.
|
this index intentionally avoids enumerating internals that rework replaces.
|
||||||
|
|
||||||
|
## ADR-0025 exemption
|
||||||
|
|
||||||
|
`bin/wakeup-poll` is a second `bin/` entry point alongside the `bin/os-backlog`
|
||||||
|
dispatcher — a deviation from [ADR-0025](../../docs/adr/0025-standard-ruby-structure-for-cc-os-plugins-lib-single-dispatcher-bin-fail-soft-installed-gem-only-dependencies.md)'s
|
||||||
|
single-dispatcher rule. This is **grandfathered**, following the same
|
||||||
|
exemption mechanism os-adr recorded for its own ADR-0025 deviation (see
|
||||||
|
`plugins/os-adr/CLAUDE.md`): the split is backed by
|
||||||
|
[ADR-0034](../../docs/adr/0034-cross-project-filing-file-dont-fix-with-a-derived-global-project-index.md)
|
||||||
|
(global project index),
|
||||||
|
[ADR-0035](../../docs/adr/0035-issue-triggered-project-ai-wakeup-via-polling-not-webhooks.md)
|
||||||
|
(issue-triggered wakeup via polling), and
|
||||||
|
[ADR-0036](../../docs/adr/0036-tmux-session-convention-for-ai-run-sessions-cc-project-purpose.md)
|
||||||
|
(tmux session convention) — "Pilot only" per the script's header comment,
|
||||||
|
not an oversight. Don't
|
||||||
|
fold `wakeup-poll` into the dispatcher as a drive-by; revisit if/when those
|
||||||
|
ADRs graduate past pilot.
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,6 @@ module Backlog
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [String, nil] the explicit board name override, if configured
|
|
||||||
def board
|
|
||||||
@data["board"]
|
|
||||||
end
|
|
||||||
|
|
||||||
# @return [String, nil] the tracker key (e.g. "forgejo:owner/repo"), if configured
|
# @return [String, nil] the tracker key (e.g. "forgejo:owner/repo"), if configured
|
||||||
def tracker
|
def tracker
|
||||||
@data["tracker"]
|
@data["tracker"]
|
||||||
|
|
@ -42,7 +37,6 @@ module Backlog
|
||||||
@data["board_id"]
|
@data["board_id"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def configured? = !board.nil?
|
|
||||||
def tracker_configured? = !tracker.nil?
|
def tracker_configured? = !tracker.nil?
|
||||||
|
|
||||||
# @return [Hash] a copy of the parsed config data
|
# @return [Hash] a copy of the parsed config data
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,21 @@
|
||||||
require_relative "test_helper"
|
require_relative "test_helper"
|
||||||
|
|
||||||
class ConfigTest < Minitest::Test
|
class ConfigTest < Minitest::Test
|
||||||
def test_nil_contents_is_unconfigured
|
def test_nil_contents_has_no_tracker
|
||||||
config = Backlog::Config.new(nil)
|
config = Backlog::Config.new(nil)
|
||||||
refute config.configured?
|
refute config.tracker_configured?
|
||||||
assert_nil config.board
|
assert_nil config.tracker
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_blank_contents_is_unconfigured
|
def test_reads_legacy_yaml_style_key
|
||||||
config = Backlog::Config.new(" \n")
|
config = Backlog::Config.new("---\ntracker: forgejo:jared/cc-os\n")
|
||||||
refute config.configured?
|
assert config.tracker_configured?
|
||||||
end
|
assert_equal "forgejo:jared/cc-os", config.tracker
|
||||||
|
|
||||||
def test_reads_board_key
|
|
||||||
config = Backlog::Config.new("board=llf-schema\n")
|
|
||||||
assert config.configured?
|
|
||||||
assert_equal "llf-schema", config.board
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_reads_legacy_yaml_style_board_key
|
|
||||||
config = Backlog::Config.new("---\nboard: llf-schema\n")
|
|
||||||
assert config.configured?
|
|
||||||
assert_equal "llf-schema", config.board
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_lines_without_separator_are_ignored
|
def test_lines_without_separator_are_ignored
|
||||||
config = Backlog::Config.new("# comment\njunk line\n")
|
config = Backlog::Config.new("# comment\njunk line\n")
|
||||||
refute config.configured?
|
assert_empty config.to_h
|
||||||
end
|
|
||||||
|
|
||||||
def test_contents_without_board_key_is_unconfigured
|
|
||||||
config = Backlog::Config.new("other=value\n")
|
|
||||||
refute config.configured?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_reads_tracker_key
|
def test_reads_tracker_key
|
||||||
|
|
@ -41,7 +25,7 @@ class ConfigTest < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tracker_unconfigured_when_absent
|
def test_tracker_unconfigured_when_absent
|
||||||
config = Backlog::Config.new("board=llf-schema\n")
|
config = Backlog::Config.new("other=value\n")
|
||||||
refute config.tracker_configured?
|
refute config.tracker_configured?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -52,11 +36,11 @@ class ConfigTest < Minitest::Test
|
||||||
|
|
||||||
def test_merge_preserves_other_keys
|
def test_merge_preserves_other_keys
|
||||||
existing = "board=llf-schema\nother=kept\n"
|
existing = "board=llf-schema\nother=kept\n"
|
||||||
updated_contents = Backlog::Config.merge(existing, "tracker", "planka:llf-schema")
|
updated_contents = Backlog::Config.merge(existing, "tracker", "forgejo:jared/cc-os")
|
||||||
updated = Backlog::Config.new(updated_contents)
|
updated = Backlog::Config.new(updated_contents)
|
||||||
|
|
||||||
assert_equal "llf-schema", updated.board
|
assert_equal "llf-schema", updated.to_h["board"]
|
||||||
assert_equal "planka:llf-schema", updated.tracker
|
assert_equal "forgejo:jared/cc-os", updated.tracker
|
||||||
assert_equal "kept", updated.to_h["other"]
|
assert_equal "kept", updated.to_h["other"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -82,7 +66,7 @@ class ConfigTest < Minitest::Test
|
||||||
|
|
||||||
def test_merge_normalizes_existing_spaced_lines_on_rewrite
|
def test_merge_normalizes_existing_spaced_lines_on_rewrite
|
||||||
existing = "version = 1\nhub = my-hub\n"
|
existing = "version = 1\nhub = my-hub\n"
|
||||||
updated_contents = Backlog::Config.merge(existing, "tracker", "planka:board")
|
updated_contents = Backlog::Config.merge(existing, "tracker", "forgejo:jared/demo")
|
||||||
updated_contents.each_line do |line|
|
updated_contents.each_line do |line|
|
||||||
next if line.strip.empty?
|
next if line.strip.empty?
|
||||||
|
|
||||||
|
|
@ -91,26 +75,26 @@ class ConfigTest < Minitest::Test
|
||||||
updated = Backlog::Config.new(updated_contents)
|
updated = Backlog::Config.new(updated_contents)
|
||||||
assert_equal "1", updated.to_h["version"]
|
assert_equal "1", updated.to_h["version"]
|
||||||
assert_equal "my-hub", updated.to_h["hub"]
|
assert_equal "my-hub", updated.to_h["hub"]
|
||||||
assert_equal "planka:board", updated.tracker
|
assert_equal "forgejo:jared/demo", updated.tracker
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_board_id_reader
|
def test_board_id_reader
|
||||||
config = Backlog::Config.new("tracker=planka:board\nboard_id=42\n")
|
config = Backlog::Config.new("tracker=forgejo:jared/demo\nboard_id=42\n")
|
||||||
assert_equal "42", config.board_id
|
assert_equal "42", config.board_id
|
||||||
assert_nil Backlog::Config.new(nil).board_id
|
assert_nil Backlog::Config.new(nil).board_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_set_preserves_comments_and_blank_lines
|
def test_set_preserves_comments_and_blank_lines
|
||||||
existing = "# managed by cc-os\ntracker=planka:board\n\n# stamped by os-status\nversion=3\n"
|
existing = "# managed by cc-os\ntracker=forgejo:jared/demo\n\n# stamped by os-status\nversion=3\n"
|
||||||
updated = Backlog::Config.set(existing, "board_id", "42")
|
updated = Backlog::Config.set(existing, "board_id", "42")
|
||||||
assert_equal "# managed by cc-os\ntracker=planka:board\n\n# stamped by os-status\nversion=3\nboard_id=42\n",
|
assert_equal "# managed by cc-os\ntracker=forgejo:jared/demo\n\n# stamped by os-status\nversion=3\nboard_id=42\n",
|
||||||
updated
|
updated
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_set_replaces_existing_key_in_place
|
def test_set_replaces_existing_key_in_place
|
||||||
existing = "# top comment\nboard_id=old\ntracker=planka:board\n"
|
existing = "# top comment\nboard_id=old\ntracker=forgejo:jared/demo\n"
|
||||||
updated = Backlog::Config.set(existing, "board_id", "new")
|
updated = Backlog::Config.set(existing, "board_id", "new")
|
||||||
assert_equal "# top comment\nboard_id=new\ntracker=planka:board\n", updated
|
assert_equal "# top comment\nboard_id=new\ntracker=forgejo:jared/demo\n", updated
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_set_normalizes_spaced_key_value_lines_only
|
def test_set_normalizes_spaced_key_value_lines_only
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,13 @@ severity, and category.
|
||||||
especially after a design/decision settles.
|
especially after a design/decision settles.
|
||||||
8. **tracker-routing** — mid-session follow-up work (a concrete task, bug, or deferred
|
8. **tracker-routing** — mid-session follow-up work (a concrete task, bug, or deferred
|
||||||
item not done this session) left as a TODO comment or chat mention instead of captured
|
item not done this session) left as a TODO comment or chat mention instead of captured
|
||||||
to the tracked board; durable spec text routed to a Planka card description (or task
|
as an issue on the repo's configured tracker (`.cc-os/config` tracker key,
|
||||||
state routed to git issues) against the Planka-state/git-issues-spec boundary
|
`os-backlog:capture`); an AI-authored issue carrying state labels or the human-curated
|
||||||
(ADR-0033, `.cc-os/config` tracker key); or a Planka card visibly accreting spec-like
|
`next` label it shouldn't (ADR-0042 — git issues are the single tracker, `next` is
|
||||||
decisions in comments with no promotion flag raised to the user — silent promotion
|
human-only, the AI never adds or removes it short of an explicit direct request); or an
|
||||||
counts too. Convention compliance only, not whether the routing choice was wise.
|
issue visibly accreting scope/decisions in comments with no promotion flag raised to the
|
||||||
|
user — silent promotion counts too. Convention compliance only, not whether the routing
|
||||||
|
choice was wise.
|
||||||
|
|
||||||
## Per-session report format (return exactly this)
|
## Per-session report format (return exactly this)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# os-vault write-behavior eval — unprompted vault-write discrimination (held-out)
|
# os-vault write-behavior eval — unprompted vault-write discrimination (held-out)
|
||||||
|
|
||||||
_Last updated: 2026-07-06 — harness built (WS2); baseline grid NOT yet run._
|
_Last updated: 2026-07-07 — harness built (WS2), baseline grid run, and the
|
||||||
|
wording loop complete and shipped; run-set and reserve are now contaminated for
|
||||||
|
future wording tuning (see `eval/results/`)._
|
||||||
|
|
||||||
Measures whether the model **unprompted** (a) writes evergreen cross-project knowledge to
|
Measures whether the model **unprompted** (a) writes evergreen cross-project knowledge to
|
||||||
the SecondBrain vault when it surfaces during normal work, and (b) writes it with
|
the SecondBrain vault when it surfaces during normal work, and (b) writes it with
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ except Exception: # pragma: no cover - yaml is provided via graphify
|
||||||
CONFIG_PATH = os.path.expanduser("~/.claude/plugins/os-vault/config.yaml")
|
CONFIG_PATH = os.path.expanduser("~/.claude/plugins/os-vault/config.yaml")
|
||||||
|
|
||||||
DEFAULT_VAULT_PATH = "~/Documents/SecondBrain"
|
DEFAULT_VAULT_PATH = "~/Documents/SecondBrain"
|
||||||
DEFAULT_GRAPHIFY_OUTPUT_DIR = "~/Documents/SecondBrain/.graphify"
|
DEFAULT_GRAPHIFY_OUTPUT_DIR = "~/Documents/SecondBrain/graphify-out"
|
||||||
DEFAULT_MODEL = "qwen25-coder-7b-16k"
|
DEFAULT_MODEL = "qwen25-coder-7b-16k"
|
||||||
DEFAULT_STALE_DAYS = 7
|
DEFAULT_STALE_DAYS = 7
|
||||||
DEFAULT_MEMSEARCH_DIR = "~/.memsearch"
|
DEFAULT_MEMSEARCH_DIR = "~/.memsearch"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue