Skip to content

feat(context): PR-D C1a — activate agents/commands override + render lift (ADR-0008)#628

Merged
memtomem merged 2 commits intomainfrom
feat/pr-d-c1a
Apr 30, 2026
Merged

feat(context): PR-D C1a — activate agents/commands override + render lift (ADR-0008)#628
memtomem merged 2 commits intomainfrom
feat/pr-d-c1a

Conversation

@memtomem
Copy link
Copy Markdown
Owner

@memtomem memtomem commented Apr 30, 2026

Summary

PR-D C1a in the ADR-0008 wiki layer series. Removes the PR-C gate
(_PR_C_ACTIVE_TYPES) and lifts wiki/override.py:render_seed_bytes
so agents and commands seed via the vendor generator path that PR-D-prep
(#627) already wired into the fan-out. Skills behavior is unchanged.

PR-D split per the canonical plan (pr-d-glistening-sketch.md):

  • C1a (this PR): gate flip + render lift + 4 test inverts + 4 new render_seed_bytes tests.
  • C1b (next): mm wiki agent override / mm wiki command override CLI mirror + ~20 mirror tests. Deferred because including it would push C1 past the ~280 LOC target.
  • C2/C3/C4: mm context update / status / install --all / migrate (subsequent PRs).

What changed

  • context/override.py — drop _PR_C_ACTIVE_TYPES + the gate branch. resolve() now returns paths for every row in OVERRIDE_FORMATS.
  • context/_names.py — drop the gate-mention comment; tighten ("commands", "codex") placeholder rationale to point at the runtime NotImplementedError since the gate is gone.
  • wiki/override.pyrender_seed_bytes lifts the skills-only NotImplementedError. Path (b) parse + render: reuses PR-C's layout-aware parse_canonical_agent / parse_canonical_command + the existing AGENT_GENERATORS / COMMAND_GENERATORS registry rather than widening the generator API surface with a new render_from_canonical(Path) helper. Function-body imports dodge a wiki ↔ context cycle (context.install already imports wiki.store).
  • ("commands", "codex") keeps an explicit NotImplementedError since GENERATOR_VENDOR has no codex_commands entry — preserves the diagnostic UX vs a silent KeyError.
  • test_context_override.py — invert the 4 gate-pin tests:
  • test_wiki_override.py (new, 4 tests) — render_seed_bytes for agents/codex (TOML), commands/gemini (TOML), the codex commands NotImplementedError placeholder pin, and the traversal-name rejection guard (added in fixup; see below).

3-assertion marker pattern (Step 2 of TDD-ish ordering)

PR-D-prep #627 used a 2-assertion symmetric pin (positive marker present + negative !=). PR-D extends to 3 assertions:

  1. canonical body absent (b"Body of the agent." not in body)
  2. override marker present (b"OVERRIDE_MARKER_AGENT" in body)
  3. byte-equality (body == override_body)

Catches three failure modes: (1) stale canonical leak, (2) wrong override file picked, (3) byte-level corruption. Extension of feedback_pin_invert_symmetric_assertion.

Known limitations (deferred to C1b)

  • _dropped fields from vendor renderers are silently discarded.
    Gemini renderer drops tools / skills / model; codex agents drops
    tools / skills / isolation / kind / temperature. Users editing
    the override file won't realize which fields the vendor runtime can't
    represent until C1b surfaces them via stderr WARNING. Inline comment
    in render_seed_bytes flags this as the follow-up.

API change

  • render_seed_bytes raises NotImplementedError with a new message
    format for ("commands", "codex") (was: skills-only NotImplementedError
    pre-PR-D, with message "override seeding for {asset_type!r} lands in a follow-up PR"). Internal API — no external callers expected.
  • render_seed_bytes parameter rename _vendorvendor (was unused
    for skills-only path; now load-bearing for vendor dispatch). Internal API.
  • render_seed_bytes now calls validate_name on entry (defense-in-depth;
    see fixup below). Idempotent with seed_override's validate.

Behavior change

  • Manually placed <project>/.memtomem/<type>/<name>/overrides/<vendor>.<ext>
    files (which had no effect under the PR-C gate) now activate. No CLI
    created these for agents/commands before C1b, so unlikely in practice;
    worth flagging since the gate flip is the activation point.

Fixup commit

fixup(c1a): defense-in-depth validate_name in render_seed_bytes + follow-up notes
(0aca0d4). Self-review caught: render_seed_bytes is in __all__ and
constructs store.root / asset_type / name / ... paths. A traversal-shaped
name from a direct caller (bypassing seed_override) would escape the
wiki root. PR-D C1a is the first PR where the agents/commands branch is
live, so this is the right ship to defend at the function boundary.

  • validate_name(name, kind=...) at function entry. Idempotent with
    seed_override's existing validate.
  • New test_render_seed_bytes_rejects_traversal_name covers all 3 asset
    types with traversal-shaped names.
  • Inline comment about _dropped follow-up.

Test plan

  • uv run pytest packages/memtomem/tests/test_context_override.py -v — 13 pass (4 inverted + 9 unchanged).
  • uv run pytest packages/memtomem/tests/test_wiki_override.py -v — 4 pass (new file; 3 + traversal guard).
  • uv run pytest packages/memtomem/tests/test_wiki_cmd_override.py -v — 10 pass (skills CLI surface unchanged).
  • uv run pytest packages/memtomem/tests/ -m "not ollama" -q — 3453 pass, 46 deselected. No regressions.
  • uv run ruff check packages/memtomem/src packages/memtomem/tests — clean.
  • uv run ruff format --check packages/memtomem/src packages/memtomem/tests — clean.
  • Cycle smoke implicit: test_render_seed_bytes_* exercise function-body imports at call time; ImportError would surface there.
  • CI green (waiting).

Out of scope

  • C1b (CLI mirror) — separate PR, depends on C1a merge.
  • C2 installed_at capture move (PR-B contract micro-fixup) — first sub-commit of the C2 PR.
  • ADR-0008 status update — final PR in the series.

🤖 Generated with Claude Code

pandas-studio and others added 2 commits May 1, 2026 08:08
…lift (ADR-0008)

PR-C #624 shipped the override resolver + matrix gated to skills via
``_PR_C_ACTIVE_TYPES``; PR-D-prep #627 added the agents/commands fan-out
application sites as dead code under the same gate. PR-D C1a removes
the gate and lifts the ``wiki/override.py`` ``NotImplementedError`` so
agents and commands seed via the vendor generator (``parse_canonical_*``
+ ``gen.render``), reusing PR-C's layout-aware parsers rather than
widening the generator API surface.

- ``context/override.py``: drop ``_PR_C_ACTIVE_TYPES`` + the if-branch.
  ``resolve()`` now returns paths for all rows in ``OVERRIDE_FORMATS``.
- ``context/_names.py``: drop the gate-mention comment; tighten the
  ``("commands", "codex")`` placeholder rationale to point at the
  runtime ``NotImplementedError`` instead of the gate.
- ``wiki/override.py``: ``render_seed_bytes`` lifts the skills-only
  ``NotImplementedError``. Function-body imports of
  ``AGENT_GENERATORS`` / ``COMMAND_GENERATORS`` (and the
  ``parse_canonical_*`` helpers) dodge a wiki ↔ context cycle, since
  ``context.install`` already imports ``wiki.store``. ``("commands",
  "codex")`` keeps an explicit ``NotImplementedError`` since
  ``GENERATOR_VENDOR`` has no ``codex_commands`` entry — preserves the
  diagnostic UX rather than falling back to a silent ``KeyError``.
- ``test_context_override.py``: invert the 4 PR-C/PR-D-prep gate-pin
  tests. Each rename keeps the original test name in the docstring
  for series-PR archive value (PR-C #624 + PR-D-prep #627). The 2
  fan-out tests use a 3-assertion marker pattern (canonical body
  absent + override marker present + byte-equality) — extension of
  ``feedback_pin_invert_symmetric_assertion`` beyond the 2-assertion
  positive+negative form that PR-D-prep #627 used.
- ``test_wiki_override.py`` (new): 3 tests for ``render_seed_bytes`` —
  agents/codex (TOML format identity), commands/gemini (TOML), and
  the codex commands ``NotImplementedError`` placeholder pin.

C1b (``mm wiki agent override`` / ``mm wiki command override`` CLI
mirror) splits to a follow-up PR — adding it would have pushed C1 past
the canonical PR-D-glistening-sketch ~280 LOC target.

Co-Authored-By: Claude <[email protected]>
…low-up notes

PR #628 self-review: ``render_seed_bytes`` is in ``__all__`` and constructs
``store.root / asset_type / name / ...`` paths from the ``name`` parameter.
``seed_override`` (the usual caller) already validates, but a direct call
with ``name = "../../etc/passwd"`` would otherwise traverse out of the wiki
root. PR-D C1a is the first PR where the agents/commands path-construction
code is live (PR-D-prep #627 added it under the ``_PR_C_ACTIVE_TYPES`` gate),
so this is the right ship to defend at the function boundary rather than
relying on caller discipline.

- ``render_seed_bytes`` calls ``validate_name`` on entry. Idempotent with
  ``seed_override``'s validate (same kind string, same name).
- New test ``test_render_seed_bytes_rejects_traversal_name`` covers all 3
  asset types with traversal-shaped names.
- Inline comment near the ``_dropped`` discard sites flags C1b as the
  follow-up that will surface dropped vendor fields via stderr WARNING.

Co-Authored-By: Claude <[email protected]>
@memtomem memtomem merged commit eee3948 into main Apr 30, 2026
7 checks passed
@memtomem memtomem deleted the feat/pr-d-c1a branch April 30, 2026 23:30
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants