Repository navigation
MEMBERS-ROSTER-001A — Safe membership-roster CSV export projection (source only, unused) #403
Description
Parent: #116 (MEMBERS-ROSTER-001 — officer-only member roster view and safe CSV export).
This is a source-only, unused, conservative safe-by-default scoped slice of #116 — the same pattern as the merged children of #92/#122/#124 (e.g. #401→#402 INSTAGRAM-002A, #400 EVENTS-001A). It lands the CSV-serialization mechanism for a membership roster export as one pure, deterministic, node:util-only CommonJS module plus an exhaustive negative-heavy test, imported by nothing. It does not wire any route, query, capability gate, audit event, or deploy — those remain owned by parent #116 and its dependencies.
Scope of this slice (mechanism, not policy)
functions/membershipRosterProjection.js — projectMembershipRosterCsv(evidence):
- Column allowlist projection (allowlist, never denylist). The output columns come from a closed registry of owner-shaped column profiles. Any row key that is not in the selected profile is silently dropped from output — a protected/sensitive field that appears in a source row can never leak into the CSV, even if added to source documents later. False-negative-safe: a borderline field is withheld, never emitted.
- Spreadsheet formula-injection neutralization (CWE-1236). Any cell whose first character is a formula lead (
=+-@TAB CR) is prefixed with a leading apostrophe so Google Sheets / Excel treat it as text. - RFC4180 structural safety. Every field is always-quoted and internal quotes doubled; embedded commas/quotes/newlines round-trip; records are CRLF-separated.
- Cell content safety. Rejects NUL/other C0/DEL/C1 control chars and U+2028/U+2029 (allows only TAB/LF/CR inside quoted cells); rejects non-string cells (callers pre-stringify); over-length cells rejected.
- Bounds (DoS guards). Max rows, max keys per row, max cell length, max total output length — all enforced.
- Hostile-input hardening. Proxy rejection, own-enumerable-data-descriptor-only reads (getters never invoked), prototype/inherited-key rejection, array-hole rejection, exact-key envelope validation. On any invalid evidence it throws one fixed frozen typed error that never echoes input.
- Frozen versioned surface (
membershipRosterSchemaVersion, frozen error class + column-profile enum + profile registry + factory export).
Policy stays with the owner. The seed column profiles in this module are a conservative minimum. Parent #116 selects one owner-approved column profile from #110; that approved profile replaces or extends this seed registry. This contract owns the mechanism (safe serialization) and never the policy (which columns/fields/access are approved).
Explicitly NOT in this slice (stays in #116)
- Officer-only website view, live canonical membership query + current-term rule.
membership_roster_view/membership_exportcapability, MFA / recent-authentication, stated purpose.- Append-only server-side audit event per export attempt.
- Direct authenticated download / short-lived one-use capability; filename policy.
- Firestore Rules, deployment, and
runmprc.comverification.
None of #116's acceptance criteria are claimed as satisfied by this slice.
Safety / deploy posture
The module is imported by nothing (functions/index.js does not require it) — it has zero runtime behavior and nothing awaits deploy. It is landed first so the eventual #116 wiring is a mechanical hookup of an already-proven serializer rather than net-new safety judgment.
Claim protocol
Creation is not a claim on #116. This child is a source-only engineering slice; a timestamped CLAIMED comment will be posted here before the implementation files are edited, per the parent's protocol. Owner approval of roster fields/access (#110) remains a separate prerequisite for #116 production-readiness.
Activity
daliu commentedon Jul 21, 2026
CLAIMED by Claude Code (daliu) at 2026-07-21T09:08:44Z; branch
members-roster-001a-csv-projection; PR #404.Source-only engineering slice only — the pure
projectMembershipRosterCsvserialization mechanism, imported by nothing. This claim does not claim parent #116, whose full implementation stays gated on its dependencies, an owner-approved column profile (#110), a scoped capability + MFA/recent-auth, per-export audit, the authenticated download flow, and deploy verification.MEMBERS-ROSTER-001A: safe membership-roster CSV export projection, so…