Skip to content

feat: resolve SecID-Service backlog (#11, #20, #22, #44) - #64

Merged
kurtseifried merged 2 commits into
mainfrom
feat/service-backlog-11-20-22-44
Nov 5, 2026
Merged

kurtseifried merged 2 commits into
mainfrom
feat/service-backlog-11-20-22-44

Conversation

@kurtseifried

Copy link
Copy Markdown
Contributor

Agent: Gemini (SecID governing agent)

Summary

Resolves the 4 open issues in the SecID-Service backlog plus ?lang= qualifier parity for URL-less RegistryResult notes:

  1. Closes CI: bump actions/checkout@v4 and actions/setup-node@v4 (Node 20 deprecation) #20 — CI Node 24 Action Bumps (ADR-016):

    • Bumped actions/checkout (v4 → de0fac2e4500dabe0009e67214ff5f5447ce83dd # v7.0.1) and actions/setup-node (v4 → 48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v7.1.0) across .github/workflows/ci.yml and .github/workflows/registry-kv-upload.yml with immutable commit SHAs ahead of GitHub's Node 20 deprecation deadline.
  2. Closes secid_FEEDBACK KV writes set no expirationTtl — the 30-day policy was only applied to the error store #22 — secid_FEEDBACK KV Retention & Resource Doc Sync (ADR-017):

    • Open feedback items remain persistent (no expirationTtl) until triaged so nothing silently expires.
    • Added resolveFeedback(kv, id, status) and RESOLVED_FEEDBACK_TTL_SECONDS = 2_592_000 (30 days) in src/feedback.ts so resolved/wontfix items expire automatically 30 days after triage.
    • Updated stale documentation across OPERATIONAL-RESOURCES.md, BACKUP-RESOURCES.md, and INTERFACE-RESOURCES.md.
  3. Closes Resolver returns empty results for namespace-level entity queries with empty match_nodes #11 — Empty match_nodes Namespace Metadata (ADR-018) & ?lang= URL-less Filter Parity:

    • When a namespace-level query (parsed.name === null && parsed.subpath === null) matches a file whose match_nodes is empty ([]), the resolver now returns status: "found" with a namespace-level RegistryResult containing official_name, common_name, alternate_names, urls, and notes, with source_count: 0 in the API response.
    • Added "alternate_names" to UNTRUSTED_TEXT_KEYS in src/sanitize.ts.
    • Updated applyQualifierFilters in src/resolver.ts so ?lang= excludes URL-less RegistryResult entries (matching content_type and parsability) and checks buildLangNotFoundMessage when filtered === null.
  4. Closes Pilot: MCP tool change log (describe_changes since a timestamp) + tool contract hashes #44 — MCP Tool Change Log (describe_changes) & Contract Hashes (ADR-019):

    • Added src/tool-changes.ts with deterministic FNV-1a 64-bit contract hashing (computeToolContractHash, buildToolMeta) and structured change history (TOOL_CHANGE_LOG, queryToolChanges).
    • Every tool in tools/list now includes _meta: { "secid/contractHash": "fnv1a64:...", "secid/lastChanged": "..." }.
    • Added the read-only describe_changes MCP tool (readOnlyHint: true, idempotentHint: true, openWorldHint: false) accepting optional since (ISO 8601) and tool parameters.

Verification

  • npm run typecheck: passed (0 errors)
  • npx vitest run: 17 test files, 1,350 passed, 0 failed
  • Added unit and E2E tests in test/feedback.test.ts, test/mcp.test.ts, test/resolver.test.ts, test/sanitize.test.ts, test/country-filter.test.ts, and e2e/mcp.spec.ts.

Two-Review Summary

  1. Self-review (Gemini): Checked all diffs against REVIEW.md and AGENTS.md invariants (escaping/sanitization on alternate_names, X-Content-Type-Options: nosniff, immutable SHA pinning on GitHub Actions, read-only MCP annotations, and parity with SecID-Server-API).
  2. Independent review (OpenAI Codex — codex review --base main):
    • Finding 1 (P2 — src/api.ts): isEmptyNamespaceListing checked results.length === 1 && !("url" in results[0]) && Array.isArray(results[0].data?.urls), which could misclassify a single URL-less source node that happens to carry data.urls as a 0-source namespace listing. Fix: Tightened isEmptyNamespaceListing to also require firstResult.data.weight === undefined and normalized firstResult.secid === decodedQueryTarget. Added unit test in test/resolver.test.ts.
    • Finding 2 (P2 — src/tool-changes.ts): TOOL_CHANGE_LOG omitted the lookup tool (#11 changes namespace-level lookup responses from not_found to found), leaving lookup's _meta["secid/lastChanged"] at the initial baseline. Fix: Added a 2026-11-04T00:00:00Z lookup change entry in TOOL_CHANGE_LOG and documented the behavior in LOOKUP_DESCRIPTION.

… tool contract hashes, feedback TTL, Node 24 actions (#11, #20, #22, #44)

- Return a single namespace-level metadata result (official_name,
  common_name, alternate_names, notes, urls, wikidata, wikipedia,
  source_count: 0, optional country) in listSources() when match_nodes
  is empty, and relocate alternate_names under registry_text_untrusted
  across the MCP boundary (#11).
- Add MCP tool contract hashes (io.cloudsecurityalliance.secid/contractHash
  and io.cloudsecurityalliance.secid/changed) to tools/list _meta via
  RFC 8785 JCS SHA-256 and add the describe_changes(since?) MCP tool (#44).
- Add resolveFeedback(kv, id, resolutionNote?) with a 30-day KV TTL on
  resolved feedback items while keeping open inbox items without TTL,
  and update OPERATIONAL-RESOURCES.md, BACKUP-RESOURCES.md, and
  INTERFACE-RESOURCES.md (#22).
- Bump actions/checkout to v7.0.1 and actions/setup-node to v7.1.0
  (SHA-pinned Node 24 releases) across CI and deploy workflows (#20).
- Record ADR-016, ADR-017, ADR-018, and ADR-019 in DECISIONS.md.

Fixes #11
Fixes #20
Fixes #22
Fixes #44

AI-Agent: Gemini
…less RegistryResult

- Tighten isEmptyNamespaceListing in src/api.ts to require exact normalized secid match and absence of source weight
- Add 2026-11-04T00:00:00Z lookup tool change entry to TOOL_CHANGE_LOG and update LOOKUP_DESCRIPTION
- Exclude URL-less RegistryResult notes when ?lang= qualifier is active in applyQualifierFilters and check buildLangNotFoundMessage when filtered is null
- Update AGENTS.md and REVIEW.md for 5 MCP tools, src/tool-changes.ts, and alternate_names in UNTRUSTED_TEXT_KEYS
- Seed secid:* name_index in test/country-filter.test.ts and add regression tests

AI-Agent: Gemini
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant