Skip to content

Deck reader: case-insensitive node names and .equiv pseudonyms (documented) #156

Closed

Description

@rjwalters

Problem

User's Guide §1.1: "Everything is case INsensitive". §1.3: "Uppercase is converted to lower case". The guide's own §1.2 deck defines N3 and later writes .equiv nin n3. Our reader matches node names case-sensitively, a recorded choice in docs/fasthenry-compat.md ("Node/element names case-sensitive"), so that deck fails with unknown node 'n3'. 2 of the 19 runnable example decks stop here.

Measured (self-authored decks):

  1. Names are case-insensitive everywhere: node definitions, segment endpoints, .external, .equiv, and in-plane node names. Output names are lowercased. Defining n1 and then N1 is a duplicate-definition error.
  2. There are no forward references. A segment endpoint, .external or .equiv naming a node defined on a later line is an error. This matches ours.
  3. .equiv pseudonyms (documented §1.3.7: "If any of the node names are not previously defined, then they become pseudonyms for those nodes in the list which are defined"):
    • .equiv nalias n3 lets nalias be used in .external and as a later segment endpoint;
    • an undefined name in the middle of the list works;
    • all names undefined is an error ("No real nodes in equiv statement");
    • defining a node after it became a pseudonym is a duplicate error.
  4. .equiv chains transitively (ours already does).
  5. .equiv n2 n2 is only a warning in FastHenry. Ours errors.

Expected

  • All modes (documented): fold node names to lowercase for matching, so N1/n1 becomes a duplicate-name error, never two nodes. Output keeps the deck's first spelling or lowercases it; pick one and document it. Implement .equiv pseudonym creation for not-yet-defined names, with the "no defined node in .equiv" error when none exist. Keep the no-forward-reference errors.
  • --fasthenry-compat only: .equiv x x becomes a warning. Native mode: error, as now.
  • Note that this reverses the compat-table decision. A native deck that relied on N1 ≠ n1 now gets an explicit duplicate error rather than a silent reinterpretation.

Acceptance criteria

  • Mixed-case references resolve in every position (segment ends, .external, .equiv, in-plane nodes).
  • Case-only duplicates are an error.
  • Pseudonym tests: alias first, alias last, alias in the middle, all-undefined error, define-after-alias error.
  • Compat: .equiv x x warns.
  • Compat-table "case-sensitive" row reversed, with rationale.

Clean-room provenance

Specified from the public FastHenry User's Guide / nonuniform ground-plane manual and from black-box runs of a locally built FastHenry on self-authored decks (2026-10-05, research for #74). No FastHenry source or distributed example deck was consulted or quoted; implement from this spec and the public docs only (CONTRIBUTING.md). Found by tools/fasthenry_compare.py over the FastHenry example corpus (#74).

Part of #76.

Implementation Guidance

Curation refresh, 2026-10-06: implementation is already proposed in PR #164. Review that PR against this scope rather than starting a second implementation. Its reported test results are not independently re-run by this curation pass.

Centralize node-name normalization in the name registry so declarations and references share the same rule. Pseudonyms should point to existing node slots without creating geometry. Choose a defined node from anywhere in an .equiv list before processing undefined names; retain transitive alias resolution and slot compaction. A compat self-equivalence warning must not prevent later entries in the same list from being joined. Include the named nodes in contact equiv_rect and contact connection when checking in-plane name handling. Document the chosen output spelling; explicit port labels and this reader's extension group= names are outside this node-name change.

Affected Files

  • fasterhenry-cli/src/inp.rs — name registry, .equiv parsing, node reference/definition paths, parser documentation and unit tests.
  • fasterhenry-cli/src/cli.rs — keep compatibility help consistent with the self-equivalence warning behavior.
  • docs/fasthenry-compat.md — revise node-name and .equiv rows and explain the documented behavior replacing the previous decision.
  • CHANGELOG.md — record the observable parser compatibility changes.

Test Plan

  • Parser tests compare mixed-case and lowercase self-authored decks in native and compat modes, including segment endpoints, .external, .equiv, ordinary in-plane nodes and named contact-area nodes.
  • Check ordinary/in-plane case-only collisions and define-after-pseudonym collisions produce line-numbered errors.
  • Exercise alias first/last/middle, mixed-case aliases, all-undefined .equiv, and transitive chains; verify aliases add no extra geometry and yield the same solved deck as direct node references.
  • Preserve unknown-node errors for segment and port forward references; .equiv pseudonyms must not permit an all-undefined list.
  • Native self-equivalence still errors; compat emits a warning and continues joining later names in the list, including names already joined transitively.
  • Verify default port-label spelling matches the documented choice and explicit labels retain their spelling.
  • Run cargo test -p fasterhenry-cli, cargo fmt --all -- --check, and cargo clippy --workspace --all-targets -- -D warnings using the repository's isolated Cargo target workflow. Use only self-authored fixtures per CONTRIBUTING.md.

Verified corrections

  • 2026-10-06, verified against origin/main @ e5d924abb67d149f1f3a066678078c36af2c3e7e (source inspection of Names::{define,lookup}, Parser::apply_equiv, apply_external, apply_node, and apply_plane_corner_form in fasterhenry-cli/src/inp.rs): registry keys currently use exact strings; .equiv looks up every name and rejects equal resolved slots. Ordinary and corner-form in-plane declarations both reach Names::define. These paths establish the parser locations above; they are not a fresh measurement of FastHenry behavior.
  • 2026-10-06, verified via GitHub REST (GET /repos/2AMLogic/fasterhenry/pulls/164 and /pulls/164/files): PR Deck reader: case-insensitive node names and .equiv pseudonyms #164 is open at head 2b47666f163c387ca5ffdd8478fbb27f70d7278c, references this issue, and modifies the four files above. All four exist on the fetched build base (git ls-tree -r origin/main --name-only). Duplicate checking reported this related PR; the open backlog has no eligible sibling micro-issue to consolidate.

Activity

  1. added
    loom:issueApproved for work. Applied by: humans, Champion, sweep gate — see curator.md.
    on Oct 5, 2026
  2. added
    loom:buildingBuilder is implementing this issue. Applied by: Builder only (claim label).
    and removed
    loom:issueApproved for work. Applied by: humans, Champion, sweep gate — see curator.md.
    on Oct 6, 2026
  3. loom-fleet-dispatch commented on Oct 6, 2026

    @loom-fleet-dispatch
    Contributor

    This issue's loom:building claim was acquired by sweep sweep-issue-156-1791246242 on host host-d9142cf3 at 2026-10-06T00:24:04.848185+00:00. This comment is a lease record (Issue #6179, Epic #6165) — its liveness signal is this comment's own forge-assigned updated_at, never a timestamp embedded in this text. See defaults/docs/lease-record.md for the format contract this establishes, and defaults/docs/lease-renewal.md for how the owning sweep keeps it fresh for the lifetime of its claim. Nothing reads this record yet (write-only, Phase 1) — a future phase will use it to decide reclamation of an abandoned claim.

    loom dashboard

  4. added
    loom:issueApproved for work. Applied by: humans, Champion, sweep gate — see curator.md.
    loom:curatingCurator is enhancing this issue. Applied by: Curator only (claim label).
    and removed
    loom:buildingBuilder is implementing this issue. Applied by: Builder only (claim label).
    on Oct 6, 2026
  5. loom-fleet-dispatch commented on Oct 6, 2026

    @loom-fleet-dispatch
    Contributor

    Curated 2026-10-06: retained the approved behavior and added Implementation Guidance, Affected Files, Test Plan, and dated source/API verification. Included named contact-area nodes in the test guidance. Related implementation PR #164 is already open; this pass did not independently run its tests. The premise gate returned out-of-scope, duplicate checking found that related PR, and all four affected paths exist on fetched origin/main. No eligible sibling scope requires consolidation. Retaining loom:issue because this is a non-material planning refresh.

    loom dashboard

  6. added
    loom:curatedCurator-enriched, awaiting approval. Additive; coexists with loom:issue. Applied by: Curator only.
    tier:goal-advancingDirectly implements a milestone deliverable or unblocks goal work
    and removed
    loom:curatingCurator is enhancing this issue. Applied by: Curator only (claim label).
    on Oct 6, 2026
  7. added a commit that references this issue on Oct 7, 2026
    56abbb2
  8. removed
    tier:goal-advancingDirectly implements a milestone deliverable or unblocks goal work
    on Oct 13, 2026
  9. removed
    tier:goal-advancingDirectly implements a milestone deliverable or unblocks goal work
    on Oct 14, 2026
  10. added
    loom:importantPriority 2 of 3: taken before unlabeled work, not a hold. Applied by: operator, Guide, Champion.
    on Oct 15, 2026
  11. loom-fleet-dispatch commented on Oct 16, 2026

    @loom-fleet-dispatch
    Contributor

    This issue is being worked by an in-session /loom:sweep run sweep-insession-s757588-11385491 on host host-6d9efa8b, published at 2026-10-16T00:22:18Z. This comment is a lease record (Issue #6320, Epic #6165) in the identical format loom-daemon's dispatch-time write uses (#6179) — its liveness signal is this comment's own forge-assigned updated_at, never the timestamp in this text. It is renewed by sweep-lease-renew.sh (#6180) for as long as this sweep's own process is alive, and simply ages out afterwards. Readers: the daemon's reclamation gate (#6286) refuses to reclaim this claim while the lease is fresh, dispatch-time ordering (#6287) yields to it, and sweep-lease-fence.sh (#6309) fences this sweep's own push/PR-open against it. See defaults/docs/lease-record.md.

  12. removed
    loom:issueApproved for work. Applied by: humans, Champion, sweep gate — see curator.md.
    on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    loom:curatedCurator-enriched, awaiting approval. Additive; coexists with loom:issue. Applied by: Curator only.loom:importantPriority 2 of 3: taken before unlabeled work, not a hold. Applied by: operator, Guide, Champion.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions