[E00-S04-T01] TypeBox/Ajv schema #182

Closed
opened 2026-08-27 00:08:42 +00:00 by kpcto · 10 comments
Owner

Parent story: [E00-S04] Configuration service (#61)

Intent

Define the configuration schema with TypeBox/Ajv.

Acceptance criteria

  • configuration schema is defined with TypeBox/Ajv
  • schema covers the validated config fields

Explicitly out of scope

  • field-specific startup error (E00-S04-T02)
  • secret redaction (E00-S04-T03)
  • process.env access rule (E00-S04-T04)

Test plan

  • validate a full config against the TypeBox/Ajv schema

Rollback note

  • revert the schema definition

Owning stream

platform

Risk quadrant

agent-full

> Parent story: [E00-S04] Configuration service (#61) ## Intent Define the configuration schema with TypeBox/Ajv. ## Acceptance criteria - configuration schema is defined with TypeBox/Ajv - schema covers the validated config fields ## Explicitly out of scope - field-specific startup error (E00-S04-T02) - secret redaction (E00-S04-T03) - process.env access rule (E00-S04-T04) ## Test plan - validate a full config against the TypeBox/Ajv schema ## Rollback note - revert the schema definition ### Owning stream platform ### Risk quadrant agent-full
kpcto added this to the Sprint 0 milestone 2026-08-27 00:08:42 +00:00
kpcto added the
status
ready
kind
task
labels 2026-08-27 00:08:42 +00:00
bot-dispatcher added
status
proposed
and removed
status
ready
kind
task
labels 2026-08-27 00:08:43 +00:00
Member

Auto-reverted by dispatcher: DoR lint: required section "Intent" is empty; required section "Acceptance criteria" is empty; required section "Explicitly out of scope" is empty; required section "Test plan" is empty; required section "Rollback note" is empty; acceptance criteria: no bullet assertions found

status/ready may only be applied by a human maintainer.

> Auto-reverted by dispatcher: DoR lint: required section "Intent" is empty; required section "Acceptance criteria" is empty; required section "Explicitly out of scope" is empty; required section "Test plan" is empty; required section "Rollback note" is empty; acceptance criteria: no bullet assertions found `status/ready` may only be applied by a human maintainer.
kpcto added the
kind
task
label 2026-08-27 21:25:05 +00:00
kpcto added
status
ready
and removed
status
proposed
labels 2026-08-30 02:15:24 +00:00
bot-dispatcher added
loop
1
status
in-progress
and removed
status
ready
labels 2026-08-30 02:15:32 +00:00
Member
agent: dispatcher
phase: complete
plan_summary: Dispatch #182: [E00-S04-T01] TypeBox/Ajv schema (platform, security-gated)
```yaml agent: dispatcher phase: complete plan_summary: Dispatch #182: [E00-S04-T01] TypeBox/Ajv schema (platform, security-gated) ```
bot-dispatcher added the needs/security-reviewneeds/security-review labels 2026-08-30 02:15:32 +00:00
Member
agent: implementer
phase: start
issue: 182
task: "[E00-S04-T01] TypeBox/Ajv schema"
plan:
  - "Create packages/config (@personal-blog/config): TypeBox configSchema covering the validated config fields (host, port, databaseUrl, sessionSecret) + Ajv-compiled validateConfig boundary"
  - "Pin golden-tuple deps exactly (@sinclair/typebox@0.34.52, ajv@8.20.0) and regenerate pnpm-lock.yaml"
  - "Wire the new package: Dockerfile manifest copy, package-set fixtures, config-schema CI job"
  - "Add tests/config-schema.test.mjs: static assertions + mutation probes + deterministic probe validating a full config against the schema (issue test plan)"
  - "Open PR with criterion→test table; verify CI green"
out_of_scope:
  - "field-specific startup error (E00-S04-T02)"
  - "secret redaction (E00-S04-T03)"
  - "process.env access rule (E00-S04-T04)"
branch: feature/182
```yaml agent: implementer phase: start issue: 182 task: "[E00-S04-T01] TypeBox/Ajv schema" plan: - "Create packages/config (@personal-blog/config): TypeBox configSchema covering the validated config fields (host, port, databaseUrl, sessionSecret) + Ajv-compiled validateConfig boundary" - "Pin golden-tuple deps exactly (@sinclair/typebox@0.34.52, ajv@8.20.0) and regenerate pnpm-lock.yaml" - "Wire the new package: Dockerfile manifest copy, package-set fixtures, config-schema CI job" - "Add tests/config-schema.test.mjs: static assertions + mutation probes + deterministic probe validating a full config against the schema (issue test plan)" - "Open PR with criterion→test table; verify CI green" out_of_scope: - "field-specific startup error (E00-S04-T02)" - "secret redaction (E00-S04-T03)" - "process.env access rule (E00-S04-T04)" branch: feature/182 ```
Member
agent: security
phase: start
issue: 182
pr: 396
scope: "Security review of PR #396 (feature/182): [E00-S04-T01] TypeBox/Ajv schema — new packages/config, CI config-schema job, tests, Dockerfile/lockfile/docs"
plan:
  - "Verify PR head 5eff1580ac79ae166495361f59f28282bf7e4515 and run gitleaks (secrets) + osv-scanner (deps) on the tree"
  - "Review the diff: packages/config sources, .gitea/workflows/ci.yml change, Dockerfile, pnpm-lock.yaml, test suite"
  - "Authz/input trace: schema validation boundary, new endpoints (none expected), injection/deserialization surface"
  - "Check review-checklist tripwire for the CI workflow change against the #390-#395 precedent"
  - "Post final verdict YAML comment (approve | request-changes with severity + findings)"
```yaml agent: security phase: start issue: 182 pr: 396 scope: "Security review of PR #396 (feature/182): [E00-S04-T01] TypeBox/Ajv schema — new packages/config, CI config-schema job, tests, Dockerfile/lockfile/docs" plan: - "Verify PR head 5eff1580ac79ae166495361f59f28282bf7e4515 and run gitleaks (secrets) + osv-scanner (deps) on the tree" - "Review the diff: packages/config sources, .gitea/workflows/ci.yml change, Dockerfile, pnpm-lock.yaml, test suite" - "Authz/input trace: schema validation boundary, new endpoints (none expected), injection/deserialization surface" - "Check review-checklist tripwire for the CI workflow change against the #390-#395 precedent" - "Post final verdict YAML comment (approve | request-changes with severity + findings)" ```
Member
agent: implementer
phase: end
issue: 182
pr: 396
result: complete
branch: feature/182
ci:
  run: 96
  status: success
  jobs: "9/9 green (incl. config-schema: 12 tests pass / 0 fail / 0 skip)"
acceptance:
  - "configuration schema is defined with TypeBox/Ajv — packages/config @personal-blog/config: configSchema defined with TypeBox (Type.Object, @sinclair/typebox@0.34.52) and compiled with Ajv (ajv@8.20.0) via validateConfig; golden-tuple exact pins"
  - "schema covers the validated config fields — host, port, databaseUrl, sessionSecret with their constraints and additionalProperties: false; locked in by static assertions + mutation probes (removing a field, making the secret optional, relaxing minLength, opening the object, dropping TypeBox/Ajv all fail)"
test_plan:
  - "validate a full config against the TypeBox/Ajv schema — deterministic probe imports the committed schema and validates a full config through Ajv (plus missing-required naming sessionSecret, short secret, unknown property, port bounds, empty databaseUrl); compiled validateConfig boundary exercised against the built package in CI"
out_of_scope_untouched:
  - "field-specific startup error (E00-S04-T02)"
  - "secret redaction (E00-S04-T03)"
  - "process.env access rule (E00-S04-T04)"
notes:
  - "server (apps/server/src/index.ts) unchanged; nothing reads process.env yet"
  - "rollback: remove packages/config + lockfile importer, revert Dockerfile manifest copy, config-schema CI job and fixture updates"
next: "await review (needs/security-review) and merge"
```yaml agent: implementer phase: end issue: 182 pr: 396 result: complete branch: feature/182 ci: run: 96 status: success jobs: "9/9 green (incl. config-schema: 12 tests pass / 0 fail / 0 skip)" acceptance: - "configuration schema is defined with TypeBox/Ajv — packages/config @personal-blog/config: configSchema defined with TypeBox (Type.Object, @sinclair/typebox@0.34.52) and compiled with Ajv (ajv@8.20.0) via validateConfig; golden-tuple exact pins" - "schema covers the validated config fields — host, port, databaseUrl, sessionSecret with their constraints and additionalProperties: false; locked in by static assertions + mutation probes (removing a field, making the secret optional, relaxing minLength, opening the object, dropping TypeBox/Ajv all fail)" test_plan: - "validate a full config against the TypeBox/Ajv schema — deterministic probe imports the committed schema and validates a full config through Ajv (plus missing-required naming sessionSecret, short secret, unknown property, port bounds, empty databaseUrl); compiled validateConfig boundary exercised against the built package in CI" out_of_scope_untouched: - "field-specific startup error (E00-S04-T02)" - "secret redaction (E00-S04-T03)" - "process.env access rule (E00-S04-T04)" notes: - "server (apps/server/src/index.ts) unchanged; nothing reads process.env yet" - "rollback: remove packages/config + lockfile importer, revert Dockerfile manifest copy, config-schema CI job and fixture updates" next: "await review (needs/security-review) and merge" ```
Member
agent: security
phase: complete
issue: 182
pr: 396
head_branch: feature/182
head_sha: 5eff1580ac79ae166495361f59f28282bf7e4515
verdict: approve
summary: >-
  No blocking security findings. The diff is a configuration-schema library
  package (TypeBox schema + Ajv-compiled validateConfig) with no routes, no
  data access, no process.env reads and no outbound requests; the schema is a
  compile-time constant (no untrusted schema reaches Ajv codegen); the CI
  change is strictly additive and matches the security-reviewed #390-#395
  pattern; scanners clean; lockfile integrity hashes verified against npm.
scanners:
  gitleaks:
    command: "gitleaks detect --source . --no-git --redact"
    result: pass
    evidence: "no leaks found (exit 0) on PR head 5eff158"
  osv-scanner:
    command: "osv-scanner --recursive ."
    result: pass
    evidence: "No issues found across 25 locked packages in pnpm-lock.yaml (exit 0)"
  semgrep:
    result: skipped
    reason: "not installed in the review image; gap covered by the manual authz/input trace below"
  integrity_verification:
    result: pass
    evidence: "all 6 new lockfile integrity hashes (@sinclair/typebox@0.34.52, ajv@8.20.0, fast-deep-equal@3.1.3, fast-uri@3.1.6, json-schema-traverse@1.0.0, require-from-string@2.0.2) verified identical to the npm registry dist.integrity"
checks:
  secrets: pass
  dependencies: pass
  authz: pass
  input_validation: pass
  injection: pass
  ssrf: pass
  unsafe_deserialization: pass
  ci_workflow: pass
authz_trace:
  new_endpoints: "none — the diff is packages/config (schema.ts/validate.ts/index.ts), a test suite, an additive CI job, a Dockerfile manifest COPY, lockfile/fixtures/docs; apps/server/src/index.ts is unchanged (still direct PORT/DATABASE_URL reads until E00-S04-T04, per the brief's out-of-scope list)"
  privilege_path: "no data access, no authz decisions, no default-allow path — validateConfig is a pure function over an unknown value with no side effects"
input_boundaries:
  schema_validation: "verified behaviorally with an independent probe against the committed src/schema.ts through Ajv 8.20.0 (Node type stripping): full config valid; missing sessionSecret rejected naming the field; short secret / unknown property / port 65536 / port 0 / port -1 / port '3000' / empty databaseUrl / null / array / wrong-typed host all rejected"
  error_leakage: "probe confirms Ajv messages name constraints, never the rejected values (short-secret error text contains no secret material); field-specific formatting (T02) and redaction (T03) are correctly deferred per the brief"
  ajv_codegen: "clean — ajv.compile() receives only the committed compile-time configSchema; no user- or env-influenced schema ever reaches the compiler"
  test_hygiene: "clean — the suite's spawnSync uses fixed argv with no shell (no command injection); the transient probe file is gitignored and removed in finally"
  ci_workflow: "clean — new config-schema job is strictly additive (+27/-0, no existing job modified); actions/checkout@v4 + actions/setup-node@v4, the same majors as all 8 pre-existing jobs; zero secrets: references and zero ${{ }} interpolation in the entire ci.yml; pnpm install --frozen-lockfile"
findings:
  - id: F1
    severity: info
    location: "packages/config/src/validate.ts:21"
    what: >-
      The Ajv instance does not set useDefaults, so the schema's defaults
      (host 0.0.0.0, port 3000) are documentation, not applied at validation
      time — validateConfig({sessionSecret}) reports valid but returns no host/port.
    exploit_path: "none (misconfiguration-shape concern only; T04's adapter owns default application)"
    fix: "None required now; when T04 lands, apply defaults explicitly in the adapter (or add useDefaults) and lock it with a test."
  - id: F2
    severity: info
    location: "tests/config-schema.test.mjs:331-336,401-411"
    what: >-
      The compiled-boundary assertions (dist/ validateConfig) are conditional
      on the package being built; on a clean local clone they skip. The CI job
      builds first, so they are deterministic in CI.
    exploit_path: "none"
    fix: "None required (documented in the PR); CI is the merge gate."
  - id: F3
    severity: info
    location: "packages/config/src/validate.ts:47"
    what: >-
      validateConfig returns raw Ajv messages; when T02 formats startup errors
      it must not echo config values into logs (T03 redaction owns this).
    exploit_path: "none today — no startup wiring exists; probe shows current messages carry no values"
    fix: "Keep the value-free message posture when T02/T03 build on this boundary."
notes:
  - >-
    CI pipeline tripwire (review-checklist): the diff touches
    .gitea/workflows/ci.yml, so it was evaluated explicitly. The change adds
    one test-runner job only — no existing job modified, no secrets context,
    no ${{ }} interpolation, same pinned action majors, frozen-lockfile
    install — identical to the pattern security-approved on #394/#395
    (additive-job precedent; explicit human sign-off for the pattern recorded
    by kpcto on issue #179 at #393). Final merge by the maintainer remains the
    human decision.
  - >-
    Criterion → test mapping verified: both acceptance criteria and the issue
    test plan map to real tests in tests/config-schema.test.mjs (static
    assertions + 6 mutation probes proving non-vacuity + deterministic
    behavioral probe); my independent probe reproduced the behavioral claims
    against the pinned ajv/typebox. Scope check: all 15 changed files are
    inside the task's brief; no unrelated changes; no existing tests deleted,
    skipped or weakened (fixture updates extend workspace package lists, which
    the new package requires).
  - >-
    Secrets posture: no secrets anywhere in the diff; the test sessionSecret
    is a dummy ('s'.repeat(32)); no process.env reads (out of scope per the
    brief). gitleaks and osv-scanner outputs captured at review start (clean,
    exit 0).

Security review of PR #396 (feature/182) for issue #182 — verdict: approve. The schema boundary is sound (required ≥32-char secret, closed object, port-range and non-empty-URL constraints all enforced and behaviorally verified; error messages never echo values), there is no new authz/injection/SSRF/deserialization surface, scanners and lockfile integrity checks are clean, and the additive CI job matches the reviewed precedent. The three findings are informational notes for the follow-up tasks (T02/T03/T04), none blocking.

```yaml agent: security phase: complete issue: 182 pr: 396 head_branch: feature/182 head_sha: 5eff1580ac79ae166495361f59f28282bf7e4515 verdict: approve summary: >- No blocking security findings. The diff is a configuration-schema library package (TypeBox schema + Ajv-compiled validateConfig) with no routes, no data access, no process.env reads and no outbound requests; the schema is a compile-time constant (no untrusted schema reaches Ajv codegen); the CI change is strictly additive and matches the security-reviewed #390-#395 pattern; scanners clean; lockfile integrity hashes verified against npm. scanners: gitleaks: command: "gitleaks detect --source . --no-git --redact" result: pass evidence: "no leaks found (exit 0) on PR head 5eff158" osv-scanner: command: "osv-scanner --recursive ." result: pass evidence: "No issues found across 25 locked packages in pnpm-lock.yaml (exit 0)" semgrep: result: skipped reason: "not installed in the review image; gap covered by the manual authz/input trace below" integrity_verification: result: pass evidence: "all 6 new lockfile integrity hashes (@sinclair/typebox@0.34.52, ajv@8.20.0, fast-deep-equal@3.1.3, fast-uri@3.1.6, json-schema-traverse@1.0.0, require-from-string@2.0.2) verified identical to the npm registry dist.integrity" checks: secrets: pass dependencies: pass authz: pass input_validation: pass injection: pass ssrf: pass unsafe_deserialization: pass ci_workflow: pass authz_trace: new_endpoints: "none — the diff is packages/config (schema.ts/validate.ts/index.ts), a test suite, an additive CI job, a Dockerfile manifest COPY, lockfile/fixtures/docs; apps/server/src/index.ts is unchanged (still direct PORT/DATABASE_URL reads until E00-S04-T04, per the brief's out-of-scope list)" privilege_path: "no data access, no authz decisions, no default-allow path — validateConfig is a pure function over an unknown value with no side effects" input_boundaries: schema_validation: "verified behaviorally with an independent probe against the committed src/schema.ts through Ajv 8.20.0 (Node type stripping): full config valid; missing sessionSecret rejected naming the field; short secret / unknown property / port 65536 / port 0 / port -1 / port '3000' / empty databaseUrl / null / array / wrong-typed host all rejected" error_leakage: "probe confirms Ajv messages name constraints, never the rejected values (short-secret error text contains no secret material); field-specific formatting (T02) and redaction (T03) are correctly deferred per the brief" ajv_codegen: "clean — ajv.compile() receives only the committed compile-time configSchema; no user- or env-influenced schema ever reaches the compiler" test_hygiene: "clean — the suite's spawnSync uses fixed argv with no shell (no command injection); the transient probe file is gitignored and removed in finally" ci_workflow: "clean — new config-schema job is strictly additive (+27/-0, no existing job modified); actions/checkout@v4 + actions/setup-node@v4, the same majors as all 8 pre-existing jobs; zero secrets: references and zero ${{ }} interpolation in the entire ci.yml; pnpm install --frozen-lockfile" findings: - id: F1 severity: info location: "packages/config/src/validate.ts:21" what: >- The Ajv instance does not set useDefaults, so the schema's defaults (host 0.0.0.0, port 3000) are documentation, not applied at validation time — validateConfig({sessionSecret}) reports valid but returns no host/port. exploit_path: "none (misconfiguration-shape concern only; T04's adapter owns default application)" fix: "None required now; when T04 lands, apply defaults explicitly in the adapter (or add useDefaults) and lock it with a test." - id: F2 severity: info location: "tests/config-schema.test.mjs:331-336,401-411" what: >- The compiled-boundary assertions (dist/ validateConfig) are conditional on the package being built; on a clean local clone they skip. The CI job builds first, so they are deterministic in CI. exploit_path: "none" fix: "None required (documented in the PR); CI is the merge gate." - id: F3 severity: info location: "packages/config/src/validate.ts:47" what: >- validateConfig returns raw Ajv messages; when T02 formats startup errors it must not echo config values into logs (T03 redaction owns this). exploit_path: "none today — no startup wiring exists; probe shows current messages carry no values" fix: "Keep the value-free message posture when T02/T03 build on this boundary." notes: - >- CI pipeline tripwire (review-checklist): the diff touches .gitea/workflows/ci.yml, so it was evaluated explicitly. The change adds one test-runner job only — no existing job modified, no secrets context, no ${{ }} interpolation, same pinned action majors, frozen-lockfile install — identical to the pattern security-approved on #394/#395 (additive-job precedent; explicit human sign-off for the pattern recorded by kpcto on issue #179 at #393). Final merge by the maintainer remains the human decision. - >- Criterion → test mapping verified: both acceptance criteria and the issue test plan map to real tests in tests/config-schema.test.mjs (static assertions + 6 mutation probes proving non-vacuity + deterministic behavioral probe); my independent probe reproduced the behavioral claims against the pinned ajv/typebox. Scope check: all 15 changed files are inside the task's brief; no unrelated changes; no existing tests deleted, skipped or weakened (fixture updates extend workspace package lists, which the new package requires). - >- Secrets posture: no secrets anywhere in the diff; the test sessionSecret is a dummy ('s'.repeat(32)); no process.env reads (out of scope per the brief). gitleaks and osv-scanner outputs captured at review start (clean, exit 0). ``` **Security review of PR #396 (`feature/182`) for issue #182 — verdict: approve.** The schema boundary is sound (required ≥32-char secret, closed object, port-range and non-empty-URL constraints all enforced and behaviorally verified; error messages never echo values), there is no new authz/injection/SSRF/deserialization surface, scanners and lockfile integrity checks are clean, and the additive CI job matches the reviewed precedent. The three findings are informational notes for the follow-up tasks (T02/T03/T04), none blocking.
bot-dispatcher removed the needs/security-reviewneeds/security-review labels 2026-08-30 02:39:40 +00:00
Member
agent: reviewer
verdict: approve
```yaml agent: reviewer verdict: approve ```
bot-dispatcher added
status
review
and removed
status
in-progress
loop
1
kind
task
labels 2026-08-30 02:40:26 +00:00
Member

Security approved; dispatching reviewer.

> Security approved; dispatching reviewer.
Member
agent: tester
phase: start
issue: 182
pr: 396
head: 5eff1580ac79ae166495361f59f28282bf7e4515
scope: "Independent probe of PR #396 (feature/182): [E00-S04-T01] TypeBox/Ajv schema — verify the two acceptance criteria without editing the implementer's tests"
plan:
  - "Check out PR head 5eff1580 and read the committed packages/config sources (schema.ts, validate.ts, index.ts, package.json, tsconfig.json)"
  - "Stand up a scratch env with the exact golden-tuple pins (@sinclair/typebox@0.34.52, ajv@8.20.0) plus typescript@6.0.3 — no edits to the repo working tree"
  - "Build the committed packages/config with tsc to a scratch outDir and run an independent behavioral probe against the compiled validateConfig boundary (full-config valid; missing/secret-short/unknown-property/port-bounds/non-integer/empty-databaseUrl rejected)"
  - "Independently assert the schema shape from the compiled configSchema (Type.Object: type object, required sessionSecret, properties host/port/databaseUrl/sessionSecret, additionalProperties: false)"
  - "Confirm CI evidence: run 96 (head 5eff1580) 9/9 green incl. the config-schema job (job 191)"
  - "Post end YAML comment with the acceptance mapping and CI links"
constraint: "never edit tests/config-schema.test.mjs or any implementer test in this PR"
```yaml agent: tester phase: start issue: 182 pr: 396 head: 5eff1580ac79ae166495361f59f28282bf7e4515 scope: "Independent probe of PR #396 (feature/182): [E00-S04-T01] TypeBox/Ajv schema — verify the two acceptance criteria without editing the implementer's tests" plan: - "Check out PR head 5eff1580 and read the committed packages/config sources (schema.ts, validate.ts, index.ts, package.json, tsconfig.json)" - "Stand up a scratch env with the exact golden-tuple pins (@sinclair/typebox@0.34.52, ajv@8.20.0) plus typescript@6.0.3 — no edits to the repo working tree" - "Build the committed packages/config with tsc to a scratch outDir and run an independent behavioral probe against the compiled validateConfig boundary (full-config valid; missing/secret-short/unknown-property/port-bounds/non-integer/empty-databaseUrl rejected)" - "Independently assert the schema shape from the compiled configSchema (Type.Object: type object, required sessionSecret, properties host/port/databaseUrl/sessionSecret, additionalProperties: false)" - "Confirm CI evidence: run 96 (head 5eff1580) 9/9 green incl. the config-schema job (job 191)" - "Post end YAML comment with the acceptance mapping and CI links" constraint: "never edit tests/config-schema.test.mjs or any implementer test in this PR" ```
kpcto added
kind
task
status
done
and removed
status
review
labels 2026-08-30 02:43:01 +00:00
Member
agent: tester
phase: end
issue: 182
pr: 396
head: 5eff1580ac79ae166495361f59f28282bf7e4515
result: pass
verdict: "acceptance criteria met — independently verified, not reliant on the implementer's own suite"
constraint_check: "no implementer test edited; working tree left clean (git status empty)"
acceptance:
  - "configuration schema is defined with TypeBox/Ajv — PASS: packages/config/src/schema.ts builds configSchema with Type.Object from @sinclair/typebox; src/validate.ts compiles it with new Ajv({ allErrors: true }) and exports validateConfig; package.json pins @sinclair/typebox@0.34.52 and ajv@8.20.0 exactly"
  - "schema covers the validated config fields — PASS: host (string, default 0.0.0.0, optional), port (integer 1..65535, default 3000, optional), databaseUrl (string minLength 1, optional), sessionSecret (string minLength 32, required), additionalProperties: false"
independent_evidence:
  - "Built the committed packages/config with tsc 6.0.3 (strict base config, NodeNext): build exit 0 and typecheck (--noEmit) exit 0"
  - "Ran an independent behavioral probe (19 checks) against the compiled validateConfig boundary: full config validates; secret-only (defaults/no-database) validates; missing sessionSecret rejected naming the field; short secret, unknown property, port 65536, port '3000', empty databaseUrl all rejected; 0 failures"
  - "Ran a raw-source probe importing the committed src/schema.ts via Node type stripping (sha256 matches committed file): full config validates through Ajv, missing sessionSecret rejected as \"must have required property 'sessionSecret'\""
ci:
  run: 96
  status: success
  url: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/96"
  config_schema_job:
    id: 191
    name: "TypeBox/Ajv config schema (E00-S04-T01)"
    url: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/96/jobs/191"
    result: "12 tests, 12 pass / 0 fail / 0 skip"
  jobs_total: "9/9 green (frozen-install, secrets-not-embedded, database-postgres-imports, migration-ledger, advisory-lock, failure-diagnostic, app-readiness, config-schema, compose-config)"
notes:
  - "No process.env reads and no startup wiring in this PR (T02/T03/T04/T05 correctly out of scope); server apps/server/src/index.ts unchanged"
  - "out_of_scope confirmed untouched: field-specific startup error (T02), secret redaction (T03), process.env access rule (T04)"
```yaml agent: tester phase: end issue: 182 pr: 396 head: 5eff1580ac79ae166495361f59f28282bf7e4515 result: pass verdict: "acceptance criteria met — independently verified, not reliant on the implementer's own suite" constraint_check: "no implementer test edited; working tree left clean (git status empty)" acceptance: - "configuration schema is defined with TypeBox/Ajv — PASS: packages/config/src/schema.ts builds configSchema with Type.Object from @sinclair/typebox; src/validate.ts compiles it with new Ajv({ allErrors: true }) and exports validateConfig; package.json pins @sinclair/typebox@0.34.52 and ajv@8.20.0 exactly" - "schema covers the validated config fields — PASS: host (string, default 0.0.0.0, optional), port (integer 1..65535, default 3000, optional), databaseUrl (string minLength 1, optional), sessionSecret (string minLength 32, required), additionalProperties: false" independent_evidence: - "Built the committed packages/config with tsc 6.0.3 (strict base config, NodeNext): build exit 0 and typecheck (--noEmit) exit 0" - "Ran an independent behavioral probe (19 checks) against the compiled validateConfig boundary: full config validates; secret-only (defaults/no-database) validates; missing sessionSecret rejected naming the field; short secret, unknown property, port 65536, port '3000', empty databaseUrl all rejected; 0 failures" - "Ran a raw-source probe importing the committed src/schema.ts via Node type stripping (sha256 matches committed file): full config validates through Ajv, missing sessionSecret rejected as \"must have required property 'sessionSecret'\"" ci: run: 96 status: success url: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/96" config_schema_job: id: 191 name: "TypeBox/Ajv config schema (E00-S04-T01)" url: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/96/jobs/191" result: "12 tests, 12 pass / 0 fail / 0 skip" jobs_total: "9/9 green (frozen-install, secrets-not-embedded, database-postgres-imports, migration-ledger, advisory-lock, failure-diagnostic, app-readiness, config-schema, compose-config)" notes: - "No process.env reads and no startup wiring in this PR (T02/T03/T04/T05 correctly out of scope); server apps/server/src/index.ts unchanged" - "out_of_scope confirmed untouched: field-specific startup error (T02), secret redaction (T03), process.env access rule (T04)" ```
kpcto closed this issue 2026-08-30 02:44:06 +00:00
Sign in to join this conversation.