feat: context_intelligence base_path relocation (multiplexed-safe)#48
feat: context_intelligence base_path relocation (multiplexed-safe)#48colombod wants to merge 4 commits into
Conversation
Make a relocated context_intelligence base_path tell the truth end-to-end —
what the hook writes is what every reader finds — and kill the confident
false-positive where a reader latched onto Amplifier core's
sessions/<id>/metadata.json (reported as a context_intelligence capture).
Mechanism (multiplexed-safe by construction):
- AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH is a read-only host/process INPUT.
The bundle NEVER writes os.environ (zero assignments) — so concurrent
sessions in one process cannot clobber each other.
- A one-line in-bundle binding base_path: "${AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH:}"
in behaviors/context-intelligence-logging.yaml carries relocation into the
writer's config (config_resolver stays pure; fold-discipline gate green).
- ONE shared canonicalizer (strip -> empty/relative -> default -> expanduser ->
absolute-or-default, never cwd) applied identically by writer and readers.
- ONE shared capture helper keyed on */sessions/*/context-intelligence/events.jsonl
(fixed-shape; subsessions counted). The events.jsonl marker is the
false-positive guard. discover.py and the workflow recipe agree on the same set.
- discover.py returns DiskScanResult{root, root_exists, disk_only_ids,
candidate_ids}; absent root is authoritative in the return (no silent zero).
- Mandatory read-only consistency check in on_session_ready warns loudly if the
env value and the resolved base_path disagree.
Behaviorally proven in a Digital Twin (no skill pytest): relocation via the
in-bundle binding, false-positive dead, reader convergence, multiplexed-safe
invariant (zero env writes), and the consistency check firing — all PASS.
Fold-gate 3/3; discover tests pass.
Known residual: relocation granularity is per-process, not per-session (a host
needing different roots per session in one process must use separate processes).
Follow-ups (deferred, intentionally not in this PR): the base-path drift-guard
lint, the broad doc-narrative sweep, and the uploader workspace-derivation edge.
🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)
Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Writer-side relocation — live E.3 proof (ROB gate)The reader half is unit-proven (33 discover tests pass). The half that was not pinned by any test is the keystone this PR promises: the writer actually relocating through the in-bundle binding, which depends on the app-cli expanding Reproduce: Deferred follow-up (intentionally not in this PR): the durable drift-guard / seam regression that makes writer != reader root impossible rather than merely loud. A bundle-internal unit test can't honestly exercise this cross-repo seam, so the live DTU run is the gate; the drift-guard is the compounding next step. |
discover_sessions now returns (rows, DiskScanResult); scripts/context-intelligence.py consumes scan.root_exists / scan.disk_only_ids. The cmd_reconstruct test mocks still returned the old (rows, list) shape, raising AttributeError: 'list' object has no attribute 'root_exists' — the real cause of the red root-test CI on PR #48. Updated all 14 mock sites to return a root_exists=True DiskScanResult, preserving disk-only ids in disk_only_ids/candidate_ids. tests/ now 729 passed, 0 failed. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…ouncil
Addresses a code review and a six-lens council review of the base_path
relocation work:
- Consistency check now fires BIDIRECTIONALLY (also when env unset but the
writer relocated via config.base_path, which env-only readers can't see);
extracted as a pure, unit-tested helper `reader_writer_roots_disagree`.
- Writer treats an unexpanded `${...}` base_path as silent default (no per-
session noise); behavior YAML documents the host `${VAR:}`-expansion contract.
- Operator-visible INFO confirmation of the active capture root when relocation
is in effect (closes the "silent misconfiguration looks like success" gap);
per-process limitation surfaced at the behavior-YAML touchpoint.
- Unified bash readers (navigation skill, navigator agent, workflow skill) onto
the canonical `events.jsonl` capture marker; fields read from sibling
metadata.json — kills the events.jsonl/metadata.json reader split-brain.
- Recipe workspace filter matches the `workspace` field (not just dir slug),
with a bounded readline (1MB) and dict guard.
- Removed dead `capture_paths_under_base`; cross-reference comments link the two
by-design-duplicated canonicalizer copies.
- New tests: tests/test_base_path_parity.py (writer≡reader parity + divergence
cases) and an end-to-end consistency/confirmation suite run against the real
amplifier_core runtime.
Verification: python_check clean; 747 root tests pass; 5 end-to-end consistency
tests pass under real amplifier_core.
Generated with [Amplifier](https://github.com/microsoft/amplifier)
Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…urce_hash) bundle.dot was stale after the base_path-relocation review + council changes. Regenerated with the structural bundle_repo_dot() generator (matching the committed convention, not LLM-enhanced) and re-rendered bundle.png; diff is the updated source_hash plus token-count deltas from the added doc/comment content. Clears the BUNDLE_DOT_STALE warning from the full validate-bundle-repo run. Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Make a relocated context_intelligence base_path tell the truth end-to-end — what the hook writes is what every reader finds — and kill the confident false-positive where a reader latched onto Amplifier core's sessions//metadata.json (reported as a context_intelligence capture).
Mechanism (multiplexed-safe by construction):
Behaviorally proven in a Digital Twin (no skill pytest): relocation via the in-bundle binding, false-positive dead, reader convergence, multiplexed-safe invariant (zero env writes), and the consistency check firing — all PASS.
Fold-gate 3/3; discover tests pass.
Known residual: relocation granularity is per-process, not per-session (a host needing different roots per session in one process must use separate processes).
Follow-ups (deferred, intentionally not in this PR): the base-path drift-guard lint, the broad doc-narrative sweep, and the uploader workspace-derivation edge.
Behavioral proof (Digital Twin)
All rows PASSED in the behavioral validation matrix.
Supersedes #37
This PR delivers the base_path-relocation intent of #37 with all needed pieces (multiplexed-safe, behaviorally proven in a Digital Twin). Closing #37 in favor of it.
🤖 Generated with Amplifier
Co-Authored-By: Amplifier 240397093+microsoft-amplifier@users.noreply.github.com
⚠ Breaking change (public API)
context_intelligence.discover_sessions()return type changed:tuple[list[dict], list[str]]—(graph_sessions, disk_only_ids)tuple[list[dict], DiskScanResult]—(graph_sessions, scan)DiskScanResultis intentionally not list-like (it forces callers to branch onscan.root_existsinstead of mistaking an empty list for success). External callers mustmigrate:
⚠ Truthiness/equality, not just unpacking.
DiskScanResultdefines no__bool__, so it isalways truthy and never
== []. Legacy code that tested the old list directly changesmeaning silently — audit those sites, not only the unpacking line:
Review fixes (addressing review of this PR)
var is unset but the writer resolved a non-default
base_path(i.e. relocation viaconfig.base_path, which the env-only readers cannot see). Previously gatedif _env_raw:,so that silent split went unwarned.
${...}base_path(host app did not expand the binding) as default silently instead of warningevery session as a bogus relative path; a genuinely-intended relocation still warns LOUD via
the consistency check. The behavior YAML documents the app-
${VAR:}-expansion requirement.workflow-pattern-analysis.yamlnow matches theworkspacefield (falling back from the fast slug path), so explicit-workspace setups are no longer
silently missed.
events.jsonlis thecanonical capture marker (matching the Python readers);
metadata.jsonis for field reads.AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH;config.base_pathis writer-side.capture_paths_under_base().Council remediations (six-lens review)
A six-lens council review (intent / simplicity / cost / reality / user / breaker) was run on
the review-fix changeset. It returned no blockers; the items below close its recorded asks.
extracted into a pure, unit-testable helper
reader_writer_roots_disagree, and the writer ≡reader canonicalizer (two copies, kept separate by the fold gate) is pinned by
tests/test_base_path_parity.py. A new end-to-end suite drives the realon_session_readyagainst the real
amplifier_coreruntime and asserts the LOUD divergence warning actuallyfires (env unset +
config.base_pathrelocated), stays silent when env matches the writer,and silent-defaults on an unexpanded
${...}.is in effect,
on_session_readynow logs (INFO — the bundle's default level) the activecapture root:
capturing to <root> (readers resolve the same root from AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH). Relocation is per-process, not per-session.It stayssilent in the default (non-relocated) case. This closes the "success and silent
misconfiguration look identical" gap; the per-process limitation is surfaced at the
behavior-YAML touchpoint.
agent, workflow-pattern-analysis skill) now enumerate captures by the canonical
events.jsonlmarker — matching the Python readers — and read fields from the siblingmetadata.json. Previously they enumerated bymetadata.json, which disagreed with the codeon partial-write edges.
readline(1 MB) and guardsisinstance(dict)so a malformed/over-long first line can neither blow up memory nor silentlydrop a session.
parity test, so a future edit to one cannot silently drift from the other.
Parked by the council's own recommendation: a full container DTU (the real-runtime harness met
the reality gate) and the CI-lane
importorskipsignal for the end-to-end suite (the core logicis already pinned in the always-run root suite).
Verification:
python_checkclean; 747 root tests pass; 5 end-to-end consistency +confirmation tests pass under the real
amplifier_coreruntime.