Three months after starting a project with PDLC, a team member asked a simple question: "What does the system look like right now?"
There was no good answer. /pdlc-arch had been run six times. The docs/02_design/architecture/ directory had six timestamped files: 20260112-arch-analysis.md, 20260204-arch-analysis.md, and so on. Each captured the architecture at a point in time. None answered the question as asked — because the question was about current state, not history.
The same thing happened with coding standards. The team ran /pdlc-standard (in the old form) to update the naming conventions. Instead of editing the existing file, it created coding-style-v2.md. Then coding-style-v3.md. By the time someone new joined the project, there were four files covering the same topic, with no obvious canonical one.
These weren't edge cases. They were a systematic confusion about what kind of artifact you're writing.
The design choice: ledger vs surface
PDLC v1.0 treated all artifacts the same way: write to a new file with a timestamp or version suffix, and never touch the old ones. This is the right behavior for some artifacts — a PRD records a decision at a point in time, and you don't want it overwritten when the feature evolves. A PRD is a ledger artifact: append-only, date-addressed, permanent.
But architecture overviews and team conventions aren't decisions. They're states. The question they answer isn't "what did we decide on Feb 4?" but "what is true right now?" For those, append-only is exactly wrong. Every new version compounds the confusion instead of resolving it.
RFC #5 introduced the ledger/surface split:
| Type | Question answered | Mutation rule | Example |
|---|---|---|---|
| Ledger | "What happened at time T?" | Append-only, never edit in place | PRD, per-feature design doc, test plan |
| Surface | "What is true right now?" | In-place edit, git log is the history |
ARCHITECTURE.md, coding standards |
The rule is enforced at the skill level. /pdlc-arch is now declared artifact_type: surface in its frontmatter. Its iron law: one file, docs/ARCHITECTURE.md, overwritten every time. The skill won't create a dated copy. If it finds legacy YYYYMMDD-arch-analysis.md files, it moves them to docs/.archive/architecture/ automatically and uses the most recent one as the starting point for the new surface file.
The same principle governs the new /pdlc-standard skill, which manages docs/00_standards/. The rule is explicit in the skill definition: coding-style-v2.md is prohibited. There is one file per topic. The audit trail lives in git log, not in filename proliferation.
Before v1.1 After v1.1
───────────────────────────────── ──────────────────────────────────
docs/02_design/architecture/ docs/
20260112-arch-analysis.md ARCHITECTURE.md ← one file
20260204-arch-analysis.md (git log shows full history)
20260315-arch-analysis.md .archive/architecture/
20260428-arch-analysis.md 20260112-arch-analysis.md
20260519-arch-analysis.md (legacy files, out of the way)
20260601-arch-analysis.md
The anti-pattern has a name now: "ledger detour" — when a surface artifact gets treated as a ledger because the tooling defaulted to append. Naming it makes it easier to catch.
The feature relation problem
v1.0 introduced per-feature state machines at docs/.pdlc-state/<feature-id>.json. Feature IDs are flat: F20260501-01, F20260501-02, and so on. Each feature tracks its own stages independently.
The problem surfaces when features start depending on each other. You're changing F20260501-03 (user authentication). Does anything else break? Under v1.0, the only way to know was to read every PRD and hope the author mentioned the dependency. There was no structural answer.
RFC #6 adds the feature relation chain via /pdlc-relate. Six relation types:
-
extends— "this feature builds on that one" -
depends_on— "this feature requires that one to function" -
supersedes— "this feature replaces that one" -
resolves— "this feature fixes that defect" -
conflicts_with— "these two features can't coexist as-is" (symmetric) -
relates_to— "loosely connected, worth knowing" (symmetric)
Relations are stored redundantly across five locations: the feature state machine JSON, the document traceability header, a reverse index at docs/.pdlc-state/_relations.json, and a generated Mermaid graph at docs/.pdlc-state/_graph.md. The redundancy is intentional — any skill can read from whichever location is most convenient, and /pdlc-relate validate checks that all five stay consistent.
The command that makes this useful is impact:
/pdlc-relate impact F20260501-03
Output:
Impact radius for F20260501-03 (user-auth)
🔴 Direct (depth 1) — must coordinate
F20260601-01 oauth-integration extends
F20260601-04 session-management depends_on
🟡 Transitive (depth ≥2) — should review
F20260612-02 user-profile-sync depends_on → F20260601-01
🟢 Historical — audit only
B20260520-07 login-loop-fix resolves
This is the answer to "what breaks if I touch this?" — with severity levels, not just a flat list. The direct layer tells you what needs coordination before you make the change. The transitive layer tells you what to review. The historical layer shows what defects this feature has already resolved, which is useful when deciding whether to edit in place or create a supersedes feature instead.
graph TD
A[F20260501-03<br/>user-auth] -->|extended by| B[F20260601-01<br/>oauth-integration]
A -->|depended on by| C[F20260601-04<br/>session-management]
B -->|depended on by| D[F20260612-02<br/>user-profile-sync]
E[B20260520-07<br/>login-loop-fix] -->|resolved by| A
style A fill:#ff6b6b,color:#fff
style B fill:#ffd93d
style C fill:#ffd93d
style D fill:#6bcb77
style E fill:#6bcb77
What to watch out for
The ledger/surface distinction is easy to misapply in one direction: marking something surface when it should be a ledger. A design decision that gets reconsidered six months later should have both the original record and the new one — not an in-place overwrite that destroys the history of the decision. If you're not sure, default to ledger. Surface is the right call only when the artifact is genuinely describing current state, not recording a decision.
For /pdlc-relate, the main friction point is bootstrapping. If you have thirty features and add the relation chain in v1.1, none of them have relation data yet. /pdlc-relate orphans will list all thirty as orphans, which is technically correct but not actionable. The practical approach is to add relations incrementally as you touch features, rather than trying to backfill the entire graph in one session.
The five-location redundancy is also worth noting as a tradeoff. Keeping relations in five places makes reads fast for any skill, but it means /pdlc-relate validate needs to run after any manual edit to catch drift. The alternative — a single source of truth that every skill reads — would require every relation lookup to go through _relations.json, which adds a dependency that wasn't there before. The current design accepts the redundancy to keep skills loosely coupled.
Where things stand
PDLC is at v1.1.0. The plugin has 33 skills (up from 31). The two new skills are additive — existing projects don't need to migrate anything to get the v1.1 behavior for /pdlc-arch. The relation chain is opt-in; if you never run /pdlc-relate, nothing changes.
Both new skills dogfood their own concepts: the docs/ARCHITECTURE.md in the pdlc-skills repo is a surface artifact maintained by /pdlc-arch, and docs/GLOSSARY.md is managed as a surface file.
The piece that's still manual: there's no automatic detection of "you're about to change a feature that has incoming depends_on edges." The impact check has to be run explicitly. Whether to put this in the /pdlc-implement guard is an open question — it would add a lookup on every implementation start, which might be more noise than signal for small projects.
Install
# New install
/claude install kanfu-panda/pdlc-skills
# Upgrade from v1.0
bash <(curl -fsSL https://raw.githubusercontent.com/kanfu-panda/pdlc-skills/main/install.sh) --upgrade
Source and issues: github.com/kanfu-panda/pdlc-skills
First article in the series: Why Hard Contracts Beat Soft Conventions When Working With AI Coding Agents
Next
Episode 03 will cover aitm — the terminal I built to solve the context-switching problem in AI-assisted coding. 5.3 MB binary, Rust + Tauri, a four-layer security model for AI command execution, and some honest notes on what the "participant not driver" framing actually costs in UX.
Top comments (0)