Skip to content

amico catalog (#111): B2 — real repertoire query + verified ingest verb - #119

Closed
aarontrowbridge wants to merge 1 commit into
b1-amico-cli-routerfrom
b2-catalog-verb
Closed

amico catalog (#111): B2 — real repertoire query + verified ingest verb#119
aarontrowbridge wants to merge 1 commit into
b1-amico-cli-routerfrom
b2-catalog-verb

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

Closes #111. Stacks on #118 (B1 — the amico verb router); base branch is b1-amico-cli-router, not main. Review/merge #118 first.

What this does

Replaces B1's catalog stub with a working spine bookkeeping verb backed by the pulse repertoire~/.amico/vaults/armonissima/catalog/pulses/<id>/metadata.toml (the amico-catalog skill's Phase-0 schema). Both subcommands are deterministic filesystem work, callable via bash by either runtime, the harness, or cron/CI:

  • amico catalog query --platform <p> --kind <g> → the incumbent pulse metadata for (platform, gate) plus the ranked candidate list (fidelity desc; ties broken by shorter duration). This is the warm-start lookup the interview does before authoring a solve.
  • amico catalog ingest --platform <p> --kind <g> [--from-run <dir>] [--artifact <file.jld2>] [--fidelity <f>] [--agree true|false] … → the promotion path, gated on verification.agree (matching the existing semantics — a run is promotable only when the independent re-rollout agreed: verification.toml agree = true). --from-run <dir> reads verification.toml (agree) + result.toml (fidelity) + defaults the artifact to <dir>/pulse.jld2; or pass --agree/--fidelity/--artifact explicitly. When gated open it promotes iff the candidate beats the incumbent (amico-catalog Version rule), writing a new {platform}-{kind}-v{N+1} entry (metadata.toml + copied pulse.jld2) with warm_start lineage back to the incumbent.

Exit codes follow the verb convention: agree ≠ trueblocked (64); verified but no beat → no-op (0); promoted → 0; usage/missing-artifact → 64.

Design

  • Pure core in repertoire.ts (loaders never throw — a corrupt/missing catalog degrades to empty, like src/catalog.ts's template/exemplar loaders); the verb body (arg parsing + writes) in catalog_verb.ts. verbs.ts wires catalog.run to it and marks it non-stub (a stub? flag so --help drops the [stub → …] tag for catalog only); vault/device/note stay B1 stubs. One impl backs both the CLI (amico.ts) and the mcp-serve facade (unchanged).
  • $AMICO_CATALOG_DIR overrides the pulses dir (tests point it at a temp catalog).

Flag-name note (S31 guard) — reviewer decision point

test/s31.test.ts bans the physics-knob double-dash flags (gate/pulse/system) anywhere in src/. So the gate discriminator is --kind (issue #111's acceptance surface; maps onto the repertoire's gate field), and the pulse-artifact path is --artifact rather than the issue's literal --pulse — a pulse-file path is not a physics knob (same category as --spec/--from-run), so it takes a non-colliding name. If you'd rather keep the literal --pulse, the alternative is an explicit, reviewed S31 carve-out amendment (the precedent mcp_serve.ts cites for spec C).

Tests

  • test/repertoire.test.ts-style pure-logic tests + query/ingest through the dist/amico.js bundle (test/catalog_verb.test.ts, 19 tests), mirroring amico.test.ts / subcommands.test.ts.
  • amico.test.ts's stub loop drops catalog (now real) and asserts it routes to query/ingest; vault/device/note still asserted as stubs.
  • amico-run: 141 passed (18 files). Extension fast suite: 435 passed, 3 skipped. Typecheck clean. No Julia-gated slow tests run (none apply to this slice).

Integration follow-up (out of scope here, per the slice)

This slice lands the CLI verb + tests only; it does not rewire the extension/interview. The remaining plugin→CLI migration: today the opencode interview has no amicode_catalog plugin tool (warm-start lookup is currently done ad hoc / not wired to the repertoire), and promotion lives in the extension's manual "Save pulse to catalog" quick-pick (run_controls.catalogPulsesDir). Issue #111's second acceptance box — "opencode interview does warm-start lookups via the CLI verb (bash)" — means wiring the interview's warm-start step to shell out to amico catalog query (and, optionally, routing promotion through amico catalog ingest so the verification.agree gate is enforced in one place). That belongs in the extension scores//plugin wiring, not amico-run, and should be its own slice/PR so this one stays reviewable.

Note: fork CI may be RED (pre-existing private-fork vendored-binary token issue), unrelated to this change.

🤖 Generated with Claude Code

Replace the B1 `catalog` stub with a working spine bookkeeping verb backed by
the pulse repertoire (~/.amico/vaults/armonissima/catalog/pulses/<id>/metadata.toml,
the amico-catalog skill's Phase-0 schema). Two subcommands, both deterministic
filesystem work callable via bash by either runtime, the harness, or cron/CI:

  amico catalog query  --platform <p> --kind <g>
      → the incumbent pulse metadata for (platform, gate) + the ranked candidate
        list (fidelity desc; ties broken by shorter duration). This is the
        warm-start lookup the interview does before authoring a solve.

  amico catalog ingest --platform <p> --kind <g> [--from-run <dir>]
                       [--artifact <file.jld2>] [--fidelity <f>] [--agree …] …
      → the PROMOTION path, GATED on verification.agree (matching the existing
        semantics — a run is promotable only when the independent re-rollout
        agreed: verification.toml `agree = true`; --from-run reads it, or pass
        --agree explicitly). When gated open it promotes iff the candidate beats
        the incumbent (amico-catalog Version rule), writing a new
        {platform}-{kind}-v{N+1} entry (metadata.toml + copied pulse.jld2) with
        `warm_start` lineage back to the incumbent. agree≠true → blocked (64);
        no beat → no-op (0); promoted → 0.

Design notes:
- Pure core in repertoire.ts (loaders never throw; a corrupt/missing catalog
  degrades to empty, like src/catalog.ts's template/exemplar loaders); the verb
  body (arg parsing + writes) in catalog_verb.ts. verbs.ts wires catalog.run to
  it and marks it non-stub; vault/device/note stay B1 stubs. One impl backs both
  the CLI (amico.ts) and the mcp-serve facade (unchanged).
- $AMICO_CATALOG_DIR overrides the pulses dir (tests point it at a temp catalog).
- FLAG NAMES honor the S31 guard (test/s31.test.ts bans the physics-knob
  double-dash flags gate/pulse/system in src/): the gate discriminator is `--kind`
  (issue #111's surface, maps to the `gate` field) and the pulse-artifact PATH is
  `--artifact` (a file path, not a physics knob — same category as spec/from-run).

Tests: repertoire pure logic + query/ingest through the dist/amico.js bundle
(mirrors amico.test.ts / subcommands.test.ts); amico.test.ts's stub loop drops
catalog (now real) and asserts it routes to query/ingest. amico-run 141 green,
extension fast suite 435 green. Stacks on #118 (B1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jack-champagne

Copy link
Copy Markdown
Member

Closing — this is already delivered. The work is on main; the PR was only ever paperwork left open by the stacked-branch flow.

b2-catalog-verb tip 0fd846d is a direct ancestor of main (d03d3c8), and git diff main...b2-catalog-verb is empty — nothing here is missing from main.

This PR targeted b1-amico-cli-router, which is itself already fully in main, so the diff shown on GitHub was never against a live base.

Branch preserved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants