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:
jared 2026-07-16 16:36:23 -04:00
parent f2fe45bab8
commit cc2f2914c5
8 changed files with 65 additions and 49 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@ graphify-out/
# Python bytecode
__pycache__/
.pytest_cache/
# autoresearch skill run logs (eval iterations)
/autoresearch/

View File

@ -20,7 +20,23 @@ module PluginConfig
private
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
def read_json(path)

View File

@ -12,3 +12,20 @@ see NOTE below.
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;
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.

View File

@ -25,11 +25,6 @@ module Backlog
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
def tracker
@data["tracker"]
@ -42,7 +37,6 @@ module Backlog
@data["board_id"]
end
def configured? = !board.nil?
def tracker_configured? = !tracker.nil?
# @return [Hash] a copy of the parsed config data

View File

@ -1,37 +1,21 @@
require_relative "test_helper"
class ConfigTest < Minitest::Test
def test_nil_contents_is_unconfigured
def test_nil_contents_has_no_tracker
config = Backlog::Config.new(nil)
refute config.configured?
assert_nil config.board
refute config.tracker_configured?
assert_nil config.tracker
end
def test_blank_contents_is_unconfigured
config = Backlog::Config.new(" \n")
refute config.configured?
end
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
def test_reads_legacy_yaml_style_key
config = Backlog::Config.new("---\ntracker: forgejo:jared/cc-os\n")
assert config.tracker_configured?
assert_equal "forgejo:jared/cc-os", config.tracker
end
def test_lines_without_separator_are_ignored
config = Backlog::Config.new("# comment\njunk line\n")
refute config.configured?
end
def test_contents_without_board_key_is_unconfigured
config = Backlog::Config.new("other=value\n")
refute config.configured?
assert_empty config.to_h
end
def test_reads_tracker_key
@ -41,7 +25,7 @@ class ConfigTest < Minitest::Test
end
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?
end
@ -52,11 +36,11 @@ class ConfigTest < Minitest::Test
def test_merge_preserves_other_keys
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)
assert_equal "llf-schema", updated.board
assert_equal "planka:llf-schema", updated.tracker
assert_equal "llf-schema", updated.to_h["board"]
assert_equal "forgejo:jared/cc-os", updated.tracker
assert_equal "kept", updated.to_h["other"]
end
@ -82,7 +66,7 @@ class ConfigTest < Minitest::Test
def test_merge_normalizes_existing_spaced_lines_on_rewrite
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|
next if line.strip.empty?
@ -91,26 +75,26 @@ class ConfigTest < Minitest::Test
updated = Backlog::Config.new(updated_contents)
assert_equal "1", updated.to_h["version"]
assert_equal "my-hub", updated.to_h["hub"]
assert_equal "planka:board", updated.tracker
assert_equal "forgejo:jared/demo", updated.tracker
end
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_nil Backlog::Config.new(nil).board_id
end
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")
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
end
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")
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
def test_set_normalizes_spaced_key_value_lines_only

View File

@ -32,11 +32,13 @@ severity, and category.
especially after a design/decision settles.
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
to the tracked board; durable spec text routed to a Planka card description (or task
state routed to git issues) against the Planka-state/git-issues-spec boundary
(ADR-0033, `.cc-os/config` tracker key); or a Planka card visibly accreting spec-like
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.
as an issue on the repo's configured tracker (`.cc-os/config` tracker key,
`os-backlog:capture`); an AI-authored issue carrying state labels or the human-curated
`next` label it shouldn't (ADR-0042 — git issues are the single tracker, `next` is
human-only, the AI never adds or removes it short of an explicit direct request); or an
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)

View File

@ -1,6 +1,8 @@
# 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
the SecondBrain vault when it surfaces during normal work, and (b) writes it with

View File

@ -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")
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_STALE_DAYS = 7
DEFAULT_MEMSEARCH_DIR = "~/.memsearch"