Skip to content

Feat/unannotated tracking sync guidance#3

Merged
Animesh-Sri-bugb merged 7 commits into
mainfrom
feat/unannotated-tracking-sync-guidance
Feb 27, 2026
Merged

Feat/unannotated tracking sync guidance#3
Animesh-Sri-bugb merged 7 commits into
mainfrom
feat/unannotated-tracking-sync-guidance

Conversation

@Animesh-Sri-bugb

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds governance workflow capabilities to GuardLink, headlined by guardlink review — an interactive command for walking through unmitigated exposures and recording formal risk decisions (accept, remediate, or skip) with mandatory justification and timestamped audit trails. Also adds clear, sync, unannotated commands, fixes the parser's shield block handling, and re-annotates the entire codebase with improved annotation quality (229 → 336 annotations, zero @accepts in source).

New commands across all three surfaces (CLI, TUI, MCP):

Command What it does
guardlink review Interactive governance review — accept/remediate/skip unmitigated exposures
guardlink clear Remove all annotations from source files (--dry-run supported)
guardlink sync Standalone agent instruction file sync
guardlink unannotated List source files with no annotations + coverage ratio

Key design decisions:

  • @accepts is write-gated behind guardlink review — agents are prohibited from writing it, enforcing human-in-the-loop governance
  • Mandatory justification for both accept and remediate prevents rubber-stamping
  • Annotations insert after the coupled block (not inline) to preserve code readability
  • MCP splits into guardlink_review_list + guardlink_review_accept with tool descriptions explicitly requiring human confirmation

Bug fix: Parser now respects @shield:begin/@shield:end blocks, preventing example annotations in template strings from being parsed as real annotations (was causing duplicate ID errors and dangling reference warnings).

Type

  • Bug fix
  • New feature
  • Annotation spec change
  • Documentation
  • CI / tooling

Checklist

  • npm run build passes
  • npm test passes
  • guardlink validate . passes (if annotations changed)
  • CHANGELOG.md updated (for user-facing changes)

Spec changes

ThreatModel schema additions (backward-compatible):

  • annotated_files: string[] — list of source files containing at least one annotation
  • unannotated_files: string[] — list of source files with no annotations

These are additive fields used by the dashboard and unannotated command. No changes to annotation syntax or existing schema fields.

- Add annotated_files/unannotated_files to ThreatModel (parser tracks coverage)
- CLI: 'guardlink unannotated' standalone command + status --not-annotated flag
- CLI: 'guardlink clear' removes annotations with --dry-run and --include-definitions
- CLI: 'guardlink sync' standalone command (was only available via MCP/TUI)
- TUI: /unannotated, /clear, /sync commands
- MCP: guardlink_unannotated, guardlink_clear, guardlink_sync tools
- Dashboard: File Coverage bar + unannotated file list on Code & Annotations page
- Templates: sync guidance in workflow section for all 7 agent formats
- Templates: tightened negative guardrail against over-annotation
- Picker: 'All of the above' as last numbered option instead of 'a' shortcut
- Auto-sync: status and validate commands auto-sync agent files after parsing
…mplates

Removed 108 annotation lines from 16 source files using guardlink clear.
Preserved: .guardlink/definitions.ts (17 assets, 20 threats, 15 controls),
tests/fixtures/, agents/prompts.ts (example annotations in prompt templates).

Previous annotations had systemic issues:
- 11 @accepts with zero @Audit pairs (rubber-stamped risk acceptances)
- Duplicate acceptances across files for same risk
- @accepts where @mitigates was correct (cli/index.ts arbitrary-write)
- Missing @exposes for accepted risks (mcp path-traversal)

Ready for re-annotation via Claude Code using updated templates that:
- Prohibit @accepts (agent writes @Audit + @comment instead)
- Require coupled annotation blocks
- Include sync guidance in workflow
Shield blocks (@shield:begin/@shield:end) now properly exclude their
content from the threat model. Previously, example annotations inside
template literal strings in prompts.ts were parsed as real annotations,
causing duplicate ID errors and dangling reference warnings.

The shield markers themselves are still emitted (for counting), but all
content between them is skipped during parsing.
24 source files annotated via Claude Code using updated templates that
prohibit @accepts and require coupled annotation blocks.

Results: 336 annotations, 64 exposures (46 mitigated, 15 open with
@Audit), 70 flows, 14 boundaries, 21 audits, 0 acceptances in source.
Agent instruction files auto-synced with current threat model context.
…ted exposures

New 'review' command across all surfaces:
  CLI: guardlink review [--list] [--severity critical,high]
  TUI: /review [severity]
  MCP: guardlink_review_list + guardlink_review_accept

Users walk through unmitigated exposures sorted by severity and choose:
  accept    — writes @accepts + @Audit with timestamped governance trail
  remediate — writes @Audit with planned-fix note
  skip      — leaves open for next review

Core module: src/review/index.ts
  - getReviewableExposures() — filters test fixtures, sorts by severity
  - applyReviewAction() — inserts annotations after coupled block
  - detectCommentStyle() — matches JSDoc, //, #, -- comment styles
  - Mandatory justification for accept and remediate (no rubber-stamping)
  - Auto-syncs agent files after annotations written

MCP tools enforce human-in-the-loop: tool descriptions explicitly state
acceptance decisions require human confirmation before calling.
- package.json / package-lock.json → 1.3.0
- MCP server version → 1.3.0
- CHANGELOG.md: full v1.3.0 entry (review, clear, sync, unannotated, shield fix)
- README.md: added review/clear/sync/unannotated to command table, updated annotation count
- GUARDLINK_REFERENCE.md: added Governance & Maintenance section
- Agent instruction files synced with updated threat model
@Animesh-Sri-bugb Animesh-Sri-bugb merged commit a711c3c into main Feb 27, 2026
3 checks passed
@Animesh-Sri-bugb Animesh-Sri-bugb deleted the feat/unannotated-tracking-sync-guidance branch April 24, 2026 22:16
Animesh-Sri-bugb added a commit that referenced this pull request May 12, 2026
Three bugs in src/mcp/lookup.ts surfaced during v1.5.0 testing where two
queries against the same identifier disagreed about whether it existed:

- `asset #login` returned 0 results when #login was referenced via
  @confirmed but never declared in definitions.ts, while `threats for
  #login` and `confirmed` both returned the joined record. (Bug 1)

- Bare `#login-sqli` returned no_match when the identifier appeared
  only as an asset/threat ref in exposures or confirmed and was never
  declared, even though `unmitigated` happily returned it. (Bug 2)

- The no_match hint contained literal double quotes that got escaped
  twice through MCP (content wrap + JSON-RPC envelope), rendering as
  \\\" in clients that print the raw response. (Bug 3)

Root cause for 1 and 2: the resolver only knew about declared entities
(model.assets/threats/controls). Now both lookupAsset and lookupFuzzy
fall back to the annotation graph (exposures, confirmed, mitigations,
acceptances, audits, flows, boundaries) and synthesize stub records
marked `declared: false` with a `referenced_in: [...]` audit trail.
Consumers can distinguish synthesized stubs from real declarations.

Bug 3 fix: the hint now uses backticks around examples instead of
double quotes, so it survives both JSON.stringify passes intact.

Adds tests/lookup.test.ts (14 tests, previously zero coverage on this
500-line module). Includes regression guards for the working queries
(unmitigated, confirmed, features, threats for) and failing-then-fixed
cases for all three bugs.

Fixes punch-list bugs #1, #2, #3. Closes test-coverage gap #16.
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