Skip to content

refactor: introduce BaseTag to simplify custom tag implementations#7

Merged
nedpals merged 4 commits into
masterfrom
claude/custom-manager-device-tag-review-jzsy1h
Jun 29, 2026
Merged

refactor: introduce BaseTag to simplify custom tag implementations#7
nedpals merged 4 commits into
masterfrom
claude/custom-manager-device-tag-review-jzsy1h

Conversation

@nedpals

@nedpals nedpals commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR introduces nfc.BaseTag, an embeddable struct that provides safe default implementations for optional Tag interface methods, significantly reducing boilerplate when implementing custom NFC tags. It also adds capability validation tooling and updates documentation to reflect the new pattern.

Key Changes

  • New BaseTag type (nfc/tag_base_default.go): Provides no-op defaults for Connect(), Disconnect(), and "not supported" errors for WriteData(), Transceive(), IsWritable(), CanMakeReadOnly(), and MakeReadOnly(). Custom tags now only need to implement four required methods: UID(), Type(), NumericType(), and ReadData().

  • Capability validation (nfc/capabilities.go): Added AssertCapabilitiesConsistent() function to detect drift between declared Capabilities() and actual method behavior (e.g., claiming CanLock: true but returning false from CanMakeReadOnly()). Performs only non-mutating checks safe for unit tests.

  • New DeviceTransceiver interface (nfc/capabilities.go): Allows devices to explicitly declare whether they support raw transceive operations, overriding the default assumption that polling devices support it.

  • Updated implementations:

    • nfc/remotenfc/tag.go: Smartphone tags now embed BaseTag instead of implementing all methods explicitly
    • nfc/tag_base.go: Removed unused connected field from pcscBaseTag
    • nfc/card.go: Removed unused preloadData() method
  • Comprehensive test coverage (nfc/tag_base_default_test.go): New tests verify BaseTag defaults work correctly and demonstrate that a minimal read-only tag needs only four methods.

  • Documentation updates (docs/extending-nfc-support.md): Completely restructured the tag implementation guide to emphasize embedding BaseTag, clarified which methods are required vs. optional, added examples showing the dramatic reduction in boilerplate, and included guidance on keeping capabilities honest.

Notable Details

  • The pattern follows capability-based design: advertise what you support via Capabilities() and only override the methods backing those capabilities
  • BaseTag is a zero-sized type with no state, making it a pure mixin with no memory overhead
  • AssertCapabilitiesConsistent() is intentionally read-only to be safe for unit tests without requiring hardware access
  • All existing code continues to work; this is purely additive with optional adoption

https://claude.ai/code/session_01NPoRipkULTkp8gnF2XSSZk

Reduce boilerplate and fix drift between the documented capability-based
philosophy and what the code actually requires.

- Add exported nfc.BaseTag with safe defaults (no-op Connect/Disconnect,
  NotSupported write/transceive/lock, false IsWritable/CanMakeReadOnly) so
  custom tags only implement UID/Type/NumericType/ReadData and override what
  they support. Refactor remotenfc.Tag to embed it, dropping 7 stub methods.
- Add DeviceTransceiver optional interface so a polling device whose Transceive
  is unsupported can report CanTransceive=false; BuildDeviceCapabilities now
  detects support instead of always asserting true.
- Add nfc.AssertCapabilitiesConsistent test helper to catch capability drift
  using non-mutating checks only.
- Remove dead code: unused pcscBaseTag.connected field and vestigial
  Card.preloadData (+ its silencer var).
- Update extending-nfc-support.md and nfc/README.md to document BaseTag,
  DeviceTransceiver, the consistency helper, and correct the inaccurate
  "tags connected on first operation" claim.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPoRipkULTkp8gnF2XSSZk
@nedpals nedpals changed the title Introduce BaseTag to simplify custom tag implementations feat: introduce BaseTag to simplify custom tag implementations Jun 29, 2026
claude added 3 commits June 29, 2026 12:53
Drop comments that merely restate the method name or duplicate the type-level
doc (remotenfc.Tag accessors, the inherited-methods note already covered by the
struct doc, and an obvious metadata-lookup comment). Keep comments that add
real information (why NumericType is 0, ReadData's NDEF-over-raw preference).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPoRipkULTkp8gnF2XSSZk
Revert the over-eager comment removal: the prior commit also deleted comments
that existed on master. Those are restored. The only comment this PR removes is
the dangling "inherited from nfc.BaseTag" note it had itself added, which merely
duplicated the Tag struct doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPoRipkULTkp8gnF2XSSZk
Drop the per-method restating comments on BaseTag (the type-level doc already
explains the override pattern) and collapse a redundant inline note that
duplicated the DeviceTransceiver interface doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPoRipkULTkp8gnF2XSSZk
@nedpals nedpals changed the title feat: introduce BaseTag to simplify custom tag implementations refactor: introduce BaseTag to simplify custom tag implementations Jun 29, 2026
@nedpals
nedpals merged commit 218122b into master Jun 29, 2026
2 of 3 checks passed
@nedpals
nedpals deleted the claude/custom-manager-device-tag-review-jzsy1h branch July 5, 2026 04:43
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