Skip to content

Global sync CLI foundations: checkable fingerprints, CONFLICT state, pdd reconcile (#1926/#1927/#1929/#1938)#1969

Open
Serhan-Asad wants to merge 39 commits into
mainfrom
integration/global-sync
Open

Global sync CLI foundations: checkable fingerprints, CONFLICT state, pdd reconcile (#1926/#1927/#1929/#1938)#1969
Serhan-Asad wants to merge 39 commits into
mainfrom
integration/global-sync

Conversation

@Serhan-Asad

Copy link
Copy Markdown
Collaborator

Global sync — CLI foundations: make prompt↔code drift checkable, and repairs path-independent

Part of the global-sync program (pdd#1932 cluster). Goal: a PR made by hand/agent and a PR made through pdd both leave the repo in agreement — and "in agreement" is a deterministic, checkable property, not a hope.

What's in here

1. Complete, committed fingerprints + epoch stamp (Issue A)

  • Every dev unit now has a committed .pdd/meta fingerprint (223 units), replacing the hand-maintained .gitignore allowlist (~48 files) that had frozen at pdd versions weeks behind the tree.
  • New scripts/stamp_fingerprints.py (stdlib, no LLM): stamp all units + --check mode. Cross-validated to 0 hash mismatches vs pdd's own hashing across all units. Writes are idempotent (unchanged unit → zero file writes, timestamp preserved).
  • CI gate in unit-tests.yml: stamp_fingerprints.py --check fails on any stale fingerprint. scripts/fingerprint_waivers.json documents the 4 legitimately-unstampable units (ambiguous leaf / no code file).

2. architecture.json completeness + bijection gate (Issue B)

  • Backfilled the missing module entries; added tests/test_architecture_completeness.py asserting module ↔ architecture.json bijection (with architecture_waivers.json for justified orphans).
  • No-arg pdd sync now enumerates previously-invisible modules.

3. Prompt-first agent instructions (Issue C)

  • AGENTS.md / CLAUDE.md / GEMINI.md now mandate: behavior change → edit the prompt first & regenerate; direct code edit → pdd update --sync-metadata + re-stamp before the PR; never hand-edit .pdd/meta or architecture.json. Closes the gap where agent instructions produced the doctrine's pdd install_completion: install_completion() got unexpected keyword argument 'quiet' #1 anti-pattern (Prompt Drift). CONTRIBUTING.md cross-referenced.

4. Surgical regeneration default (pdd#1938 / PR#1940 folded in)

  • pdd sync defaults to edit-shaped regeneration (force_incremental_flag=(not fresh)) with a new --fresh flag, instead of full "rebirth" regen that dropped declared symbols on mature modules.

5. Explicit CONFLICT state + pdd resolve (pdd#1929)

  • When prompt AND code/derived artifacts both changed since the last fingerprint, the unit is classified CONFLICT — reported with an actionable message (names the unit, what moved, the resolution commands), fingerprint/run-report preserved (no destructive delete-and-regen over manual code).
  • New pdd resolve <unit> --accept-current deterministically stamps the current tree as the agreed baseline; --prompt-wins/--code-wins are documented stubs.

6. pdd reconcile unified onto one implementation (pdd#1927)

  • Evolved the upstream pdd reconcile (fix(sync): add deterministic continuous sync reconcile #1954) to use a single hashing/resolution core (pdd's real hash functions + correct unit/path resolution), fixing two pre-existing false positives. scripts/stamp_fingerprints.py is now a thin wrapper over it (CLI contract unchanged). Adds [BASENAME], --check, --accept-current, --backfill.

7. Prompt catch-up queue + pilot (Issue A2)

  • scripts/build_prompt_catchup_queue.py ranks code-ahead units; 4 units back-propagated as a pilot. (Surfaced two upstream pdd update meta bugs — subdir meta path + nulled test hashes — noted for follow-up.)

Verification

  • Both CI gates green on the merged tree (stamp_fingerprints.py --check, test_architecture_completeness.py).
  • Live loop proven: a direct code-only edit → --check detects → pdd resolve --accept-current → green.
  • pdd reconcile/stamper idempotency verified: re-run after merging main restamped only the 25 units main changed (198 untouched).
  • Merged current origin/main in; deterministic restamp reconciled it cleanly.

Notes for review

  • Big PR by design (per team preference). The bulk of the line count is the 223 committed .pdd/meta JSON files (the epoch stamp) — the code surface is scripts/ + pdd/commands/{resolve,reconcile}.py + continuous_sync.py + the sync decision path.
  • --check now imports pdd (was stdlib-only); fine in CI. Follow-up flagged: make pdd reconcile resolution .pddrc-driven for full consumer-repo generality before a release ships it.

🤖 Generated with Claude Code

Serhan-Asad and others added 30 commits July 8, 2026 15:01
…-fresh (#1938)

pdd sync regenerated mature modules "rebirth-shaped" (full regeneration),
dropping declared public symbols. PDD already ships edit-shaped generation
(incremental_code_generator + code_patcher_LLM), but sync hardcoded
force_incremental_flag=False, so it deferred to the deliberately-conservative
diff_analyzer_LLM ("prefer complete regeneration"), which rebirthed modules on
ordinary small prompt deltas and lost symbols.

Make sync prefer surgical generation for mature modules, with a --fresh opt-out:
- New `pdd sync --fresh` flag (default off), threaded sync -> sync_main ->
  sync_orchestration and the one-session generate loop.
- Both sync generate call sites now pass force_incremental_flag=(not fresh):
  default -> surgical/edit-shaped (existing code + prompt delta -> minimal edit,
  declared symbols preserved); --fresh -> standard generation.
- Reuses existing infra only. Safety nets preserved: new/empty modules still
  full-generate; undeterminable original prompt falls back to full generation;
  conformance repair retries still force full regeneration (#1724); the
  public-surface / declared-interface gate (#1900) is unchanged and remains the
  guarantee.
- --fresh is single-module only: raises UsageError on global/agentic sync paths
  (mirrors --snapshot-context) instead of silently no-op'ing.

Prompt sources edited in tandem with generated .py (pdd is self-hosted);
sync_main's architecture.json signature aligned; README documents the flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ctions

Add a terse Prompt-First Workflow block near the top of AGENTS.md, CLAUDE.md,
and GEMINI.md so coding agents edit prompts first, regenerate with `pdd sync`,
run `pdd update --sync-metadata` to back-propagate direct code edits and
re-stamp the fingerprint before a PR, never hand-edit `.pdd/meta/*.json` or
`architecture.json`, and never delete passing tests. Removes the contradiction
where agent docs steered edits into the doctrine's #1 anti-pattern, Prompt Drift.

Part of the global-sync program (Issue C).

Co-Authored-By: Claude <noreply@anthropic.com>
Point Core Philosophy at AGENTS.md/CLAUDE.md/GEMINI.md and the doctrine
Anti-Patterns section, and align the "If editing code directly" step with the
agent rules (`pdd update --sync-metadata` re-stamp; no hand-editing metadata)
so human and agent docs agree and no longer contradict each other.

Part of the global-sync program (Issue C).

Co-Authored-By: Claude <noreply@anthropic.com>
…es (Issue C)

Reviewed against Issue C acceptance criteria: surgical blocks in AGENTS/CLAUDE/GEMINI,
CONTRIBUTING aligned to pdd update --sync-metadata, no contradictions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
architecture.json is the registry that drives project-wide `pdd sync`
(no-arg sync enumerates modules from it via _architecture_sync_modules).
27 top-level pdd/*.py modules that have BOTH a prompt and code were absent,
so global sync and dependency-ordered heal were structurally blind to them
(construct_paths, load_prompt_template, config_resolution, cli_theme,
one_session_sync, provider_manager, reasoning, edit_file, ...).

Entries are appended (no reflow of existing bytes) with:
- reason: prompt <pdd-reason> tag, else module docstring first sentence
- description: module docstring first paragraph, else prompt reason
- interface: derived from code AST (public classes + functions with
  signatures/returns), mirroring the existing module-interface schema
- dependencies: the prompt's own <include>/<pdd-dependency> declarations
  only, so `pdd checkup --validate-arch-includes` stays green (import-derived
  deps would register as declaration drift and fail that gate)
- priority: max(existing)+1..; tags: []; position omitted (54 entries omit it)

Coverage of top-level pdd modules: 152 -> 179. Sync enumeration: 188 -> 215.

Co-Authored-By: Claude <noreply@anthropic.com>
…entry

Registering load_prompt_template (previous commit) surfaced a latent
inconsistency: agentic_test_orchestrator's architecture entry listed
load_prompt_template_python.prompt as a dependency, but its prompt only
references load_prompt_template via a context-example include
(context/load_prompt_template_example.py), never via <pdd-dependency> or a
module-prompt <include>. Per the validator's own model (context/example
artifacts are not module dependencies), that dependency edge is spurious;
it stayed invisible only because load_prompt_template had no entry to map to.

Removing it keeps `pdd checkup --validate-arch-includes` green (0 -> 0
non-strict warnings). If maintainers consider it a real module dependency,
the alternative fix is a prompt-side <pdd-dependency> declaration (prompts
are out of scope for this change).

Co-Authored-By: Claude <noreply@anthropic.com>
tests/test_architecture_completeness.py asserts a module<->entry bijection:
every top-level pdd/*.py module (after .pddignore) has exactly one
architecture.json entry, unless waived in architecture_waivers.json. Also
checks every entry's filepath (code) and filename (prompt) exist on disk, and
ratchets the adjacent orphan gaps (prompt-no-code, code-no-prompt,
code-no-test) so new gaps must be documented, not silent. Two meta-tests prove
the gate has teeth (a removed entry / an unwaived new module both fail it).

architecture_waivers.json documents:
- modules_without_architecture_entry: 20 hand-written utilities / CLI wiring
  with no generating prompt (json_atomic, drift_main, __main__, ...), each with
  a one-line reason — these are exempt from the bijection.
- orphans.{prompt_without_code(16), code_without_prompt(21), code_without_test(22)}
- known_registry_exceptions: 2 pre-existing double-registrations
  (user_story_tests, coverage_contracts; merged by sync at runtime) and 2
  entries predating the description field, documented for ratchet-down.

Reuses pdd's own helpers (_load_pddignore/_is_pddignored, extract_modules,
_basename_from_architecture_filename) so the gate tracks production semantics.

Co-Authored-By: Claude <noreply@anthropic.com>
Run tests/test_architecture_completeness.py as an explicit named step in the
Unit Tests job, alongside the existing validate-arch-includes checks. The full
`pytest tests/` run already collects it; this dedicated step makes the
module<->architecture.json bijection gate visible and fast-failing.

Co-Authored-By: Claude <noreply@anthropic.com>
scripts/stamp_fingerprints.py recomputes every dev unit's fingerprint from
disk (composite prompt_hash + include_deps + code/example/test hashes) and
writes it byte-identically to how `pdd sync` persists it. It is stdlib-only
(no pdd import, no LLM): the hashing is vendored verbatim from
sync_determine_operation.py, and code/example/test paths are resolved by the
.pddrc convention plus architecture.json overrides (issue #225 filepath,
issue #1677 ambiguous-leaf stem disambiguation), so recomputed hashes match
the CLI for every unit.

--check recomputes and diffs against the committed metas, exiting non-zero on
drift or a missing/hand-edited fingerprint. This is the primitive the CI gate
and audits reuse.

scripts/fingerprint_waivers.json lists the units `pdd sync` itself cannot
fingerprint (ambiguous bare leaves cli/gate; core_dump_smoke and
server/routes/session have no code file), so --check excludes them.

tests/test_stamp_fingerprints.py pins hash parity against pdd's own
calculate_current_hashes for representative units (flat, subdir,
architecture-overridden, ambiguous-leaf), the no-trailing-newline byte format,
--check drift detection on a tampered meta, and waiver/coverage classification.

Co-Authored-By: Claude <noreply@anthropic.com>
The committed .pdd/meta/*.json set is the oracle `pdd sync` trusts for every
decision, but it was a hand-maintained `!`-allowlist pinning only ~42 of 223
units — the stalest artifact in the repo. Remove the blanket
`.pdd/meta/*.json` ignore and its per-file allowlist so every dev unit's
fingerprint is tracked. Only transient files stay ignored: atomic-write temp
files (`.pdd/meta/*.tmp`) and sync logs (via the global `*.log` rule).
Run-report tracking (`*_run.json`) is left exactly as-is (out of scope).

Document the policy in CONTRIBUTING.md: never hand-edit `.pdd/meta`;
regenerate the whole set with scripts/stamp_fingerprints.py, which CI verifies
via --check.

Co-Authored-By: Claude <noreply@anthropic.com>
One-time epoch stamp (scripts/stamp_fingerprints.py). Declares the current
tree the agreed sync baseline: recompute every unit's prompt/code/example/test
hashes so the committed .pdd/meta is a trustworthy three-way merge-base.
Refreshes 42 stale fingerprints (some pinned at 0.0.234 from May) and adds 181
that were never committed.

Pre-existing prompt/code divergence is accepted here by design (back-propagation
is a follow-up); what matters is that FUTURE drift is detected against a true
base. Verified: a mature module that previously resolved to
`fail_and_request_manual_merge` against its stale fingerprint now reports a
benign decision, and no module resolves to a phantom generate/auto-deps/update.

Co-Authored-By: Claude <noreply@anthropic.com>
Add a step to the unit-tests job that fails when any committed .pdd/meta
fingerprint is stale or missing, so the epoch stamp cannot silently rot again.
The check is stdlib-only and needs no pdd import or network.

Co-Authored-By: Claude <noreply@anthropic.com>
…mp (Issue A)

Reviewed: 0 cross-validation mismatches vs pdd's own hashing across 223 units,
--check re-run independently (exit 0), 200 tests green, gitignore allowlist gone
(run-report policy untouched), waivers minimal and justified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n gate (Issue B)

Reviewed: 27 entries backfilled (surgical append, existing entries byte-identical),
20 code-only modules waived, bijection gate with teeth-proving meta-tests, deps
authored prompt-declared to keep validate-arch-includes green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-fresh (pdd#1938)

Wave-2 dependency: the repair bot's PROMPT_AHEAD leg must not full-regen mature modules.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on, maintenance)

The commit-all fingerprint gate flagged exactly the units #1940 touched; restamped
with scripts/stamp_fingerprints.py per the new CONTRIBUTING policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…1929)

The prompt+derived co-edit branch already returns a non-destructive
fail_and_request_manual_merge / CONFLICT decision (landed in #1954). This
makes its reason self-actionable: it names the unit, states which artifacts
moved, and gives the exact 'pdd resolve <basename> --accept-current /
--prompt-wins / --code-wins' commands. details now carries basename,
language, changed_files, and a resolution_commands map for machine consumers.

analyze_conflict_with_llm is documented as reserved (not wired into the
decision path) so it is no longer a parallel auto-resolver. Prompt prose
realigned: removes the stale unlink/delete/recurse description of the old
destructive branch and describes the actionable CONFLICT contract.

Co-Authored-By: Claude <noreply@anthropic.com>
pdd resolve <basename> --accept-current deterministically stamps the current
working tree as the agreed baseline (re-fingerprint via continuous_sync's
save_fingerprint core), turning a CONFLICT unit IN_SYNC without any LLM call.
Command-level transactional: re-classifies after stamping and only reports
success when the unit lands IN_SYNC (exit 0), else non-zero.

--prompt-wins / --code-wins are documented previews of the LLM strategies
(regenerate from prompt / back-propagate to prompt): they print what WOULD run
and exit non-zero ('not yet automated'). Exactly one strategy is required.

Modeled on commands/reconcile.py (commands/ dir, no prompt) so it is exempt
from the architecture-completeness and fingerprint-stamper gates, both of which
stay green.

Co-Authored-By: Claude <noreply@anthropic.com>
Enumerate every python unit (reusing stamp_fingerprints unit resolution) and
rank the code-ahead ones -- code committed more recently than its prompt -- by
drift churn: added+deleted lines on the code file since 2026-04-01 over commits
that touched code but NOT the prompt.

75 of 229 units are code-ahead. 43 are conflict_risk: the prompt's most recent
(non-merge, in-window) commit touched the prompt but NOT the code, i.e. a
standalone prompt edit never reconciled with code by a joint commit -- pdd
update (code->prompt) there could clobber deliberate prompt intent, so these are
flagged for human review and must NOT be auto-updated. The remaining 32 are pure
staleness (prompt last synced WITH code by a joint commit, then code drifted):
safe to back-propagate.

conflict_risk uses the pathspec-free per-commit file map from the window log; a
per-unit 'git log -- <prompt>' cannot be used because the pathspec filters
--name-only down to just the prompt, hiding whether the same commit also touched
code.

scripts/build_prompt_catchup_queue.py regenerates scripts/prompt_catchup_queue.json.

Co-Authored-By: Claude <noreply@anthropic.com>
pdd update (agentic, provider=google) back-propagated code->prompt for the
code-ahead unit server/token_counter (queue rank 28, non-conflict: prompt last
synced with code by joint commit c1db8fc, then code drifted 32d). Prompt gains
a structured interface covering all 8 public functions + CostEstimate/TokenMetrics;
internal NamedTuple ModelPricing stays undeclared (was never in the prompt, not
dropped). Code untouched; tests/server/test_token_counter.py 42 passed.

Re-stamped via scripts/stamp_fingerprints.py to the subdir-qualified meta
.pdd/meta/server_token_counter_python.json (pdd update itself wrote a stray
leaf-named .pdd/meta/token_counter_python.json -- removed; see report). --check clean.

Co-Authored-By: Claude <noreply@anthropic.com>
pdd update (agentic, provider=google) back-propagated code->prompt for the
code-ahead unit commands/modify (queue rank 22, non-conflict). Detector marks it
non-conflict because its most recent RAW prompt touch is the joint commit
7f9e46c (code+prompt together); note git log -- <prompt> hides that commit via
history simplification, so raw per-commit numstat is the correct signal. All 3
public commands (split, change, update) retained. Code untouched;
tests/commands/test_modify.py 46 passed.

Re-stamped to subdir-qualified .pdd/meta/commands_modify_python.json; removed the
stray leaf-named .pdd/meta/modify_python.json pdd update wrote. --check clean.

Co-Authored-By: Claude <noreply@anthropic.com>
A dry-run previously only replayed the operation log, so a freshly-created
CONFLICT (prompt AND a derived artifact both changed since the fingerprint)
was invisible until a real sync ran. The dry-run branch now computes the
current decision read-only (log_mode=True, read_only=True — no lock, no
fingerprint/metadata mutation) via a new _display_dry_run_decision helper and
prints a 'Current analysis:' line, prefixing a CONFLICT with its actionable
resolution message.

test_dry_run_mode updated deliberately: dry-run now makes exactly one
read-only sync_determine_operation call (asserted read_only/log_mode). Adds
test_dry_run_surfaces_conflict_without_side_effects (real path, fingerprint
byte-identical after) and test_conflict_reason_surfaces_actionable_resolve_command
(the reason with 'pdd resolve' reaches result['errors']).

Prompt + meta realigned for the new dry-run behavior; both gates green.

Co-Authored-By: Claude <noreply@anthropic.com>
test_sync_determine_operation.py: assert the CONFLICT reason names the unit,
what moved, and the exact pdd resolve commands, and that details carries
basename/language/resolution_commands; a helper test covers the --language
suffix and 3-way co-edit phrasing. (Unit test_hash re-stamped since these
tests live in the unit's tracked test file.)

test_resolve_command.py (new): pdd resolve --accept-current turns a CONFLICT
IN_SYNC and stamps the CHANGED code (not the old baseline), preserving the
fingerprint; --json reports before/after; --prompt-wins/--code-wins are
documented stubs that exit non-zero and do not mutate the fingerprint;
exactly-one-strategy and unknown-unit guards.

Co-Authored-By: Claude <noreply@anthropic.com>
pdd update (agentic, provider=google) back-propagated code->prompt for the
code-ahead unit agentic_test_generate (queue rank 32, non-conflict, code 36d
ahead -- the most-stale non-conflict unit). Public entry run_agentic_test_generate
retained. Code untouched; tests/test_agentic_test_generate.py 44 passed.

Re-stamped: pdd update's meta write NULLED example_hash/test_hash/test_files
(it maintains only prompt_hash/code_hash), which fails --check; the stamper
restores the full fingerprint. --check clean.

Co-Authored-By: Claude <noreply@anthropic.com>
…1927)

Replace continuous_sync's discover_units/get_pdd_file_paths path logic with
the Wave-0 stamper's resolution (pdd/prompts rglob + architecture.json
filepath overrides + slash-basenames, each unit -> its own .pdd/meta), while
keeping pdd's real hash functions (calculate_current_hashes / save_fingerprint)
so a reconcile stamp is byte-identical to `pdd sync`. This is the single
implementation issue #1927 asks for; scripts/stamp_fingerprints.py becomes a
thin wrapper over it in a follow-up commit.

Fixes both classification false positives on the clean tree (the same tree the
CI stamper reports as fully current):
- commands/firecrawl: was FAILURE "incomplete metadata: test_hash" because the
  underscore meta-derived basename resolved the test to the stray flat
  tests/test_commands_firecrawl.py. Correct resolution -> IN_SYNC.
- core/remote_session vs remote_session: was DOC_CHANGED because both collapsed
  to one safe-basename and cross-wired fingerprints. Each now maps to its own
  meta -> IN_SYNC.

Stamping is idempotent: a unit whose content hashes already match its stored
fingerprint is not rewritten (timestamp preserved, zero writes), so a repo-wide
restamp touches only genuinely-changed units (pdd_cloud restamp-churn addendum).

Machine-readable verdicts gain the issue #884 shape (status / reasons /
affected_artifacts / remediation) alongside the existing classification fields.
CONFLICT keeps its definition (prompt-side AND code/derived-side both moved) to
stay aligned with the sync decision path (#1929).

build_report's public signature/report shape is preserved for existing callers
(ci_drift_heal, maintenance, modify dry-runs); adds accept_current/backfill.

Co-Authored-By: Claude <noreply@anthropic.com>
pdd update (agentic, provider=google) back-propagated code->prompt for the
code-ahead unit checkup_prompt_apply (queue rank 30, non-conflict). All public
symbols (ApplyFindingRecord, ApplyRunResult, apply_approved_patches) retained.
Code untouched; tests/test_checkup_prompt_apply.py 14 passed. Re-stamped;
--check clean.

Co-Authored-By: Claude <noreply@anthropic.com>
…kfill (part of #1927)

- positional [BASENAME] (keep --module as an alias) scopes a run to one unit.
- --check: read-only verification with the CI stamper's contract (exit non-zero
  on any missing/stale/no-code unit; waived+ignored excluded).
- --accept-current: stamp CONFLICT units only (explicit human acceptance of the
  current tree as the agreed baseline).
- --backfill: stamp UNBASELINED units only (missing/invalid fingerprint).
- --heal keeps stamping single-sided drift; each stamping flag is scoped to
  exactly its class (_stampable_now now gates drift on --heal).
- --json carries the issue #884 verdict shape already produced by the core.

Co-Authored-By: Claude <noreply@anthropic.com>
Reviewed: destructive both-changed branch was already neutralized upstream (#1954);
this adds the actionable message, deterministic pdd resolve --accept-current,
dry-run CONFLICT surfacing, and demotes the dead LLM conflict path. 202 tests green
on the branch; gates green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

# Conflicts:
#	.pdd/meta/metadata_sync_python.json
#	.pdd/meta/pre_checkup_gate_python.json
#	.pdd/meta/sync_determine_operation_python.json
#	.pdd/meta/sync_orchestration_python.json
Per the team-lead boundary note, continuous_sync.py and commands/reconcile.py
are owned by the sibling #1927 effort this wave. Rework pdd resolve so it no
longer imports them: classification now reuses sync_determine_operation's own
_changed_artifacts_from_hashes (keeping the CONFLICT definition — prompt-side
AND derived-side both moved vs the stored fingerprint — identical to the sync
decision path), and stamping uses the shared runtime save_fingerprint writer
directly. Tests likewise drop the continuous_sync import and assert via the
command's own --json output (before/after) plus fingerprint inspection.

Behavior and CLI surface unchanged; 8 resolve tests green, pylint 10/10, both
gates green. Any overlap with reconcile --accept-current is left for merge-time
consolidation.

Co-Authored-By: Claude <noreply@anthropic.com>
…dary fix)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Serhan-Asad and others added 9 commits July 9, 2026 13:41
…lot (Issue A2)

Reviewed: prompts+metas only (no code churn), 75-unit ranked backlog with 43
conflict-flagged units excluded from auto-update, symbol-drop checks passed,
two upstream pdd-update meta bugs documented for follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

# Conflicts:
#	.pdd/meta/agentic_test_generate_python.json
#	.pdd/meta/checkup_prompt_apply_python.json
#	.pdd/meta/commands_modify_python.json
#	.pdd/meta/server_token_counter_python.json
#1927)

The stamper no longer vendors a stdlib copy of pdd's hashing; it imports the
shared core (resolve_units / hashes_for / stamp_units / run_check) so the CI
gate and `pdd reconcile` can never diverge. The CLI contract is unchanged:
`--check` prints the same "checked N stampable units..." lines and the same exit
codes CI depends on, and the default stamp is now idempotent (unchanged units
are skipped).

Adds a small public API to continuous_sync (resolve_unit/resolve_units/
hashes_for/stamp_units) so the wrapper needs no protected-member access.

test_stamper_is_stdlib_only is inverted into test_stamper_delegates_to_
continuous_sync: the stdlib-only invariant is intentionally lifted (the team
lead's call: CI installs the package), and the new test guards that the script
imports the shared core and re-vendors no hashlib hashing. The other 15 stamper
tests pass unchanged. `stamp_fingerprints.py --check` stays green (223 current).

Co-Authored-By: Claude <noreply@anthropic.com>
…part of #1927)

tests/test_continuous_sync.py covers the four reconcile verdicts (current /
stamped / conflict / unbaselined), the --accept-current (CONFLICT-only) and
--backfill (unbaselined-only) stamping scopes, the issue #884 --json verdict
shape, idempotency (second run is a no-op; a single changed unit touches only
its own fingerprint), the two resolution regressions #1954 got wrong
(commands/firecrawl, core/remote_session vs remote_session), the reconcile CLI
(--check exit codes, BASENAME + --json), and script<->command parity on the
committed tree.

Removes the now-satisfied "TODO add tests/test_continuous_sync.py" orphan waiver
from architecture_waivers.json.

Co-Authored-By: Claude <noreply@anthropic.com>
…single impl)

Reviewed: stamper resolution ported into continuous_sync (real pdd hash fns),
two #1954 false positives fixed with regression tests, script now a thin wrapper
with byte-identical CLI contract, idempotent writes, --accept-current/--backfill
scoped. Follow-up flagged: .pddrc-driven resolution for consumer repos before
any pdd release ships this.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged 25 upstream commits; main's code changes + new story_regression units
restamped to the merged tree via scripts/stamp_fingerprints.py. Both gates green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nding 1)

commands/checkup_simplify and core/remote_session resolved to their same-named
LEAF files (pdd/checkup_simplify.py, pdd/remote_session.py) because architecture.json
had no path-qualified entry, so the resolver fell back to the leaf — the fingerprint
tracked the wrong file and edits to the real command/core file were invisible to the
gate. Add the 2 missing architecture.json entries + restamp; edits now flag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, docs

Finding 2: 'pdd resolve --accept-current' now REQUIRES a CONFLICT — single-sided
(code-only/prompt-only) drift is refused with a redirect to pdd update/pdd sync/
pdd reconcile --heal, so it can't silently baseline real drift. Added --force escape
hatch + IN_SYNC no-op. New tests cover refuse/force/no-op.

Finding 3: the CONFLICT message no longer advertises the --prompt-wins/--code-wins
preview stubs as resolutions; it points at the real runnable commands (pdd update /
pdd sync) plus pdd resolve --accept-current. Updated the prompt spec + tests.

Docs: README no longer tells users to delete .pdd/meta/*.json (contradicted the
never-hand-edit policy) — points to pdd reconcile --heal. Documented the 6
prompt-less pdd/commands wrappers (incl. resolve/reconcile) in architecture_waivers.

Restamped affected fingerprints. Gates + resolver/resolve/sync/orchestration tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ll, reconcile no-match guard

Finding 1: the CONFLICT message and pdd resolve guidance emitted invalid commands
for non-Python units — pdd sync/pdd update/pdd reconcile reject --language (only
pdd resolve accepts it), and pdd update takes the CODE FILE path, not a basename.
Fixed all sites (sync_determine_operation conflict message, resolve.py guard +
stub previews) to emit valid shapes; tests lock in no-suffix sync/update + code-path.

Finding 2: README recovery advice said 'pdd reconcile --heal', but a deleted/
invalid fingerprint is UNBASELINED and only --backfill stamps it; --heal leaves it
broken. README now points at --backfill (missing/invalid) vs --heal (drifted).

Finding 3: 'pdd reconcile <typo> --check' exited 0/ok:true with 0 units, so CI/
runbook checks could silently skip the intended unit. A targeted run that matches
no unit now errors (nonzero) with a spelling hint. New test covers it.

Restamped; gates + resolve/sync/continuous_sync/orchestration suites + lint green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant